bde68249425127f49c3f6c81a68ee324611b6b41
[rocksndiamonds.git] / src / events.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  ©1995 Artsoft Development                               *
5 *        Holger Schemel                                    *
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 *----------------------------------------------------------*
12 *  events.c                                                *
13 ***********************************************************/
14
15 #include "events.h"
16 #include "init.h"
17 #include "screens.h"
18 #include "tools.h"
19 #include "game.h"
20 #include "editor.h"
21 #include "misc.h"
22 #include "tape.h"
23 #include "joystick.h"
24
25 void EventLoop(void)
26 {
27   while(1)
28   {
29     if (XPending(display))      /* got an event */
30     {
31       XEvent event;
32
33       XNextEvent(display, &event);
34
35       switch(event.type)
36       {
37         case Expose:
38           HandleExposeEvent((XExposeEvent *) &event);
39           break;
40         case UnmapNotify:
41           SleepWhileUnmapped();
42           break;
43         case ButtonPress:
44         case ButtonRelease:
45           HandleButtonEvent((XButtonEvent *) &event);
46           break;
47         case MotionNotify:
48           HandleMotionEvent((XMotionEvent *) &event);
49           break;
50         case KeyPress:
51         case KeyRelease:
52           HandleKeyEvent((XKeyEvent *) &event);
53           break;
54         case FocusIn:
55         case FocusOut:
56           HandleFocusEvent((XFocusChangeEvent *) &event);
57           break;
58         case ClientMessage:
59           HandleClientMessageEvent((XClientMessageEvent *) &event);
60           break;
61         default:
62           break;
63       }
64     }
65     else                        /* got no event, but don't be lazy... */
66     {
67       HandleNoXEvent();
68
69       /* don't use all CPU time when idle; the main loop while playing
70          has its own synchronization and is CPU friendly, too */
71
72       if (game_status != PLAYING)
73       {
74         XSync(display, FALSE);
75         Delay(10);
76       }
77     }
78
79     if (game_status == EXITGAME)
80       return;
81   }
82 }
83
84 void ClearEventQueue()
85 {
86   while(XPending(display))
87   {
88     XEvent event;
89
90     XNextEvent(display, &event);
91
92     switch(event.type)
93     {
94       case Expose:
95         HandleExposeEvent((XExposeEvent *) &event);
96         break;
97       case UnmapNotify:
98         SleepWhileUnmapped();
99         break;
100       case ButtonRelease:
101         button_status = MB_RELEASED;
102         break;
103       case KeyRelease:
104         key_joystick_mapping = 0;
105         break;
106       case FocusIn:
107       case FocusOut:
108         HandleFocusEvent((XFocusChangeEvent *) &event);
109         break;
110       case ClientMessage:
111         HandleClientMessageEvent((XClientMessageEvent *) &event);
112         break;
113       default:
114         break;
115     }
116   }
117 }
118
119 void SleepWhileUnmapped()
120 {
121   BOOL window_unmapped = TRUE;
122
123   XAutoRepeatOn(display);
124
125   while(window_unmapped)
126   {
127     XEvent event;
128
129     XNextEvent(display, &event);
130
131     switch(event.type)
132     {
133       case Expose:
134         HandleExposeEvent((XExposeEvent *) &event);
135         break;
136       case ButtonRelease:
137         button_status = MB_RELEASED;
138         break;
139       case KeyRelease:
140         key_joystick_mapping = 0;
141         break;
142       case MapNotify:
143         window_unmapped = FALSE;
144         break;
145       case ClientMessage:
146         HandleClientMessageEvent((XClientMessageEvent *) &event);
147         break;
148       default:
149         break;
150     }
151   }
152
153   if (game_status==PLAYING)
154     XAutoRepeatOff(display);
155 }
156
157 void HandleExposeEvent(XExposeEvent *event)
158 {
159   int x = event->x, y = event->y;
160   int width = event->width, height = event->height;
161
162   if (direct_draw_on && game_status==PLAYING)
163   {
164     int xx,yy;
165     int x1 = (x-SX)/TILEX, y1 = (y-SY)/TILEY;
166     int x2 = (x-SX+width)/TILEX, y2 = (y-SY+height)/TILEY;
167
168     SetDrawtoField(DRAW_BACKBUFFER);
169
170     for(xx=0; xx<SCR_FIELDX; xx++)
171       for(yy=0; yy<SCR_FIELDY; yy++)
172         if (xx>=x1 && xx<=x2 && yy>=y1 && yy<=y2)
173           DrawScreenField(xx,yy);
174     DrawAllPlayers();
175
176     SetDrawtoField(DRAW_DIRECT);
177   }
178
179   if (soft_scrolling_on && game_status == PLAYING)
180   {
181     int fx = FX, fy = FY;
182
183     fx += (local_player->MovDir & (MV_LEFT|MV_RIGHT) ? ScreenMovPos : 0);
184     fy += (local_player->MovDir & (MV_UP|MV_DOWN)    ? ScreenMovPos : 0);
185
186     XCopyArea(display,fieldbuffer,backbuffer,gc,
187               fx,fy, SXSIZE,SYSIZE,
188               SX,SY);
189   }
190
191   XCopyArea(display,drawto,window,gc, x,y, width,height, x,y);
192
193   XFlush(display);
194 }
195
196 void HandleButtonEvent(XButtonEvent *event)
197 {
198   motion_status = FALSE;
199
200   if (event->type==ButtonPress)
201     button_status = event->button;
202   else
203     button_status = MB_RELEASED;
204
205   HandleButton(event->x, event->y, button_status);
206 }
207
208 void HandleMotionEvent(XMotionEvent *event)
209 {
210   motion_status = TRUE;
211
212   HandleButton(event->x, event->y, button_status);
213 }
214
215 void HandleKeyEvent(XKeyEvent *event)
216 {
217   int key_status = (event->type == KeyPress ? KEY_PRESSED : KEY_RELEASED);
218   unsigned int event_state = (game_status != PLAYING ? event->state : 0);
219   KeySym key = XLookupKeysym(event, event_state);
220
221   HandleKey(key, key_status);
222 }
223
224 void HandleFocusEvent(XFocusChangeEvent *event)
225 {
226   static int old_joystick_status = -1;
227
228   if (event->type == FocusOut)
229   {
230     XAutoRepeatOn(display);
231     old_joystick_status = joystick_status;
232     joystick_status = JOYSTICK_OFF;
233     key_joystick_mapping = 0;
234   }
235   else if (event->type == FocusIn)
236   {
237     if (game_status == PLAYING)
238       XAutoRepeatOff(display);
239     if (old_joystick_status != -1)
240       joystick_status = old_joystick_status;
241   }
242 }
243
244 void HandleClientMessageEvent(XClientMessageEvent *event)
245 {
246   if ((event->window == window) &&
247       (event->data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", FALSE)))
248     CloseAll();
249 }
250
251 void HandleButton(int mx, int my, int button)
252 {
253   static int old_mx = 0, old_my = 0;
254
255   if (mx<0 || my<0)
256   {
257     mx = old_mx;
258     my = old_my;
259   }
260   else
261   {
262     old_mx = mx;
263     old_my = my;
264
265     HandleVideoButtons(mx,my,button);
266     HandleSoundButtons(mx,my,button);
267     HandleGameButtons(mx,my,button);
268   }
269
270 #ifdef DEBUG
271   if (game_status == PLAYING && button)
272   {
273     int sx = (mx - SX) / TILEX;
274     int sy = (my - SY) / TILEY;
275
276     if (IN_SCR_FIELD(sx,sy))
277     {
278       int x = UNSCROLLX(sx);
279       int y = UNSCROLLY(sy);
280
281       printf("INFO: Feld[%d][%d] == %d\n", x,y, Feld[x][y]);
282       printf("      Store[%d][%d] == %d\n", x,y, Store[x][y]);
283       printf("      Store2[%d][%d] == %d\n", x,y, Store2[x][y]);
284       printf("      StorePlayer[%d][%d] == %d\n", x,y, StorePlayer[x][y]);
285       printf("\n");
286     }
287   }
288 #endif
289
290   switch(game_status)
291   {
292     case MAINMENU:
293       HandleMainMenu(mx,my,0,0,button);
294       break;
295     case TYPENAME:
296       HandleTypeName(0,XK_Return);
297       break;
298     case CHOOSELEVEL:
299       HandleChooseLevel(mx,my,0,0,button);
300       break;
301     case HALLOFFAME:
302       HandleHallOfFame(button);
303       break;
304     case LEVELED:
305       LevelEd(mx,my,button);
306       break;
307     case HELPSCREEN:
308       HandleHelpScreen(button);
309       break;
310     case SETUP:
311       HandleSetupScreen(mx,my,0,0,button);
312       break;
313     case PLAYING:
314       HandleGameActions(0);
315       break;
316     default:
317       break;
318   }
319 }
320
321 void HandleKey(KeySym key, int key_status)
322 {
323   int joy = 0;
324
325   /* Map cursor keys to joystick directions */
326
327   switch(key)
328   {
329     case XK_Left:               /* normale Richtungen */
330 #ifdef XK_KP_Left
331     case XK_KP_Left:
332 #endif
333     case XK_KP_4:
334 #ifndef MSDOS
335     case XK_J:
336 #endif
337     case XK_j:
338       joy |= JOY_LEFT;
339       break;
340     case XK_Right:
341 #ifdef XK_KP_Right
342     case XK_KP_Right:
343 #endif
344     case XK_KP_6:
345 #ifndef MSDOS
346     case XK_K:
347 #endif
348     case XK_k:
349       joy |= JOY_RIGHT;
350       break;
351     case XK_Up:
352 #ifdef XK_KP_Up
353     case XK_KP_Up:
354 #endif
355     case XK_KP_8:
356 #ifndef MSDOS
357     case XK_I:
358 #endif
359     case XK_i:
360       joy |= JOY_UP;
361       break;
362     case XK_Down:
363 #ifdef XK_KP_Down
364     case XK_KP_Down:
365 #endif
366     case XK_KP_2:
367 #ifndef MSDOS
368     case XK_M:
369 #endif
370     case XK_m:
371       joy |= JOY_DOWN;
372       break;
373 #ifdef XK_KP_Home
374     case XK_KP_Home:            /* Diagonalrichtungen */
375 #endif
376     case XK_KP_7:
377       joy |= JOY_UP | JOY_LEFT;
378       break;
379 #ifdef XK_KP_Page_Up
380     case XK_KP_Page_Up:
381 #endif
382     case XK_KP_9:
383       joy = JOY_UP | JOY_RIGHT;
384       break;
385 #ifdef XK_KP_End
386     case XK_KP_End:
387 #endif
388     case XK_KP_1:
389       joy |= JOY_DOWN | JOY_LEFT;
390       break;
391 #ifdef XK_KP_Page_Down
392     case XK_KP_Page_Down:
393 #endif
394     case XK_KP_3:
395       joy |= JOY_DOWN | JOY_RIGHT;
396       break;
397 #ifndef MSDOS
398     case XK_S:                  /* Feld entfernen */
399 #endif
400     case XK_s:
401       joy |= JOY_BUTTON_1 | JOY_LEFT;
402       break;
403 #ifndef MSDOS
404     case XK_D:
405 #endif
406     case XK_d:
407       joy |= JOY_BUTTON_1 | JOY_RIGHT;
408       break;
409 #ifndef MSDOS
410     case XK_E:
411 #endif
412     case XK_e:
413       joy |= JOY_BUTTON_1 | JOY_UP;
414       break;
415 #ifndef MSDOS
416     case XK_X:
417 #endif
418     case XK_x:
419       joy |= JOY_BUTTON_1 | JOY_DOWN;
420       break;
421     case XK_Shift_L:            /* Linker Feuerknopf */
422 #ifndef MSDOS
423     case XK_Control_L:
424     case XK_Alt_L:
425     case XK_Meta_L:
426 #endif
427       joy |= JOY_BUTTON_1;
428       break;
429     case XK_Shift_R:            /* Rechter Feuerknopf */
430 #ifndef MSDOS
431     case XK_Control_R:
432     case XK_Alt_R:
433     case XK_Meta_R:
434     case XK_Mode_switch:
435     case XK_Multi_key:
436     case XK_B:                  /* (Bombe legen) */
437 #endif
438     case XK_b:
439       joy |= JOY_BUTTON_2;
440       break;
441     default:
442       break;
443   }
444
445   if (joy)
446   {
447     if (key_status == KEY_PRESSED)
448       key_joystick_mapping |= joy;
449     else
450       key_joystick_mapping &= ~joy;
451
452     HandleJoystick();
453   }
454
455   if (game_status != PLAYING)
456     key_joystick_mapping = 0;
457
458   if (key_status == KEY_RELEASED)
459     return;
460
461   if (key==XK_Return && game_status==PLAYING && AllPlayersGone)
462   {
463     CloseDoor(DOOR_CLOSE_1);
464     game_status = MAINMENU;
465     DrawMainMenu();
466     return;
467   }
468
469   if (key==XK_Escape && game_status!=MAINMENU)  /* quick quit to MAINMENU */
470   {
471     CloseDoor(DOOR_CLOSE_1 | DOOR_NO_DELAY);
472     game_status = MAINMENU;
473     DrawMainMenu();
474     return;
475   }
476
477   if (game_status==PLAYING && (tape.playing || tape.pausing))
478     return;
479
480   switch(game_status)
481   {
482     case TYPENAME:
483       HandleTypeName(0,key);
484       break;
485     case MAINMENU:
486     case CHOOSELEVEL:
487     case SETUP:
488     {
489       switch(key)
490       {
491         case XK_Return:
492           if (game_status==MAINMENU)
493             HandleMainMenu(0,0,0,0,MB_MENU_CHOICE);
494           else if (game_status==CHOOSELEVEL)
495             HandleChooseLevel(0,0,0,0,MB_MENU_CHOICE);
496           else if (game_status==SETUP)
497             HandleSetupScreen(0,0,0,0,MB_MENU_CHOICE);
498           break;
499         default:
500           break;
501       }
502       break;
503     }
504     case HELPSCREEN:
505       HandleHelpScreen(MB_RELEASED);
506       break;
507     case HALLOFFAME:
508       switch(key)
509       {
510         case XK_Return:
511           game_status = MAINMENU;
512           DrawMainMenu();
513           BackToFront();
514           break;
515         default:
516           break;
517       }
518       break;
519     case LEVELED:
520       LevelNameTyping(key);
521       break;
522     case PLAYING:
523     {
524       switch(key)
525       {
526
527 #ifdef DEBUG
528         case XK_0:
529         case XK_1:
530         case XK_2:
531         case XK_3:
532         case XK_4:
533         case XK_5:
534         case XK_6:
535         case XK_7:
536         case XK_8:
537         case XK_9:
538           if (key == XK_0)
539             GameFrameDelay = 500;
540           else
541             GameFrameDelay = (key - XK_0) * 10;
542           printf("Game speed == %d%% (%d ms delay between two frames)\n",
543                  GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
544           break;
545
546         case XK_a:
547           if (ScrollStepSize == TILEX/8)
548             ScrollStepSize = TILEX/4;
549           else
550             ScrollStepSize = TILEX/8;
551           printf("ScrollStepSize == %d\n", ScrollStepSize);
552           break;
553
554         case XK_f:
555           ScrollStepSize = TILEX/8;
556           printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
557           break;
558         case XK_g:
559           ScrollStepSize = TILEX/4;
560           printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
561           break;
562         case XK_h:
563           ScrollStepSize = TILEX/2;
564           printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
565           break;
566         case XK_l:
567           ScrollStepSize = TILEX;
568           printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
569           break;
570
571 #ifndef MSDOS
572         case XK_Q:
573 #endif
574         case XK_q:
575           local_player->dynamite = 1000;
576           break;
577
578         case XK_x:
579
580           {
581             int i,j,k, num_steps = 8, step_size = TILEX / num_steps;
582             static long scroll_delay=0;
583             long scroll_delay_value = 4*4 / num_steps;
584
585             printf("Scroll test\n");
586
587             for(i=0;i<3;i++)
588             {
589               for(j=0;j<SCR_FIELDX;j++)
590               {
591                 for(k=0;k<num_steps;k++)
592                 {
593                   int xxx = j*TILEX+k*step_size;
594                   int done = 0;
595
596                   while(!done)
597                   {
598                     if (DelayReached(&scroll_delay, scroll_delay_value))
599                     {
600                       XCopyArea(display,fieldbuffer,window,gc,
601                                 SX+xxx,SY,
602                                 SXSIZE-xxx,SYSIZE,
603                                 SX,SY);
604                       XCopyArea(display,fieldbuffer,window,gc,
605                                 SX,SY,
606                                 xxx,SYSIZE,
607                                 SX+SXSIZE-xxx,SY);
608   
609                       XFlush(display);
610                       XSync(display,FALSE);
611
612                       done = 1;
613                     }
614                     else
615                     {
616                       Delay(1);
617                     }
618                   }
619   
620                   /*
621                   Delay(160 / num_steps);
622                   */
623                   /*
624                   Delay(120 / num_steps);
625                   */
626                 }
627               }
628             }
629           }
630
631           break;
632
633         case XK_y:
634           /*
635           {
636             printf("FX = %d, FY = %d\n", FX,FY);
637
638             XCopyArea(display,fieldbuffer,window,gc,
639                       0,0,
640                       MIN(WIN_XSIZE,FXSIZE),MIN(WIN_YSIZE,FYSIZE),
641                       0,0);
642             XFlush(display);
643             XSync(display,FALSE);
644             Delay(1000);
645           }
646           */
647
648           printf("direct_draw_on == %d\n", direct_draw_on);
649
650           break;
651
652         case XK_z:
653           {
654             int i;
655
656             for(i=0; i<MAX_PLAYERS; i++)
657             {
658               printf("Player %d:\n", i);
659               printf("  jx == %d, jy == %d\n",
660                      stored_player[i].jx, stored_player[i].jy);
661               printf("  last_jx == %d, last_jy == %d\n",
662                      stored_player[i].last_jx, stored_player[i].last_jy);
663             }
664             printf("\n");
665           }
666
667           break;
668 #endif
669
670         default:
671           break;
672       }
673       break;
674     }
675     default:
676       break;
677   }
678 }
679
680 void HandleNoXEvent()
681 {
682   if (button_status && game_status != PLAYING)
683   {
684     HandleButton(-1,-1,button_status);
685     return;
686   }
687
688   switch(game_status)
689   {
690     case MAINMENU:
691     case CHOOSELEVEL:
692     case HALLOFFAME:
693     case HELPSCREEN:
694     case SETUP:
695       HandleJoystick();
696       break;
697     case PLAYING:
698       HandleJoystick();
699
700       /*
701       HandleGameActions(0);
702       */
703
704       break;
705     default:
706       break;
707   }
708 }
709
710 void HandleJoystick()
711 {
712   int joystick  = Joystick();
713   int keyboard  = key_joystick_mapping;
714   int joy       = (tape.playing ? TapePlayAction() : (joystick | keyboard));
715   int left      = joy & JOY_LEFT;
716   int right     = joy & JOY_RIGHT;
717   int up        = joy & JOY_UP;
718   int down      = joy & JOY_DOWN;
719   int button    = joy & JOY_BUTTON;
720   int newbutton = (JoystickButton() == JOY_BUTTON_NEW_PRESSED);
721   int dx        = (left ? -1    : right ? 1     : 0);
722   int dy        = (up   ? -1    : down  ? 1     : 0);
723
724   switch(game_status)
725   {
726     case MAINMENU:
727     case CHOOSELEVEL:
728     case SETUP:
729     {
730       static long joystickmove_delay = 0;
731
732       if (joystick && !button && !DelayReached(&joystickmove_delay,15))
733         newbutton = dx = dy = 0;
734
735       if (game_status==MAINMENU)
736         HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
737       else if (game_status==CHOOSELEVEL)
738         HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
739       else if (game_status==SETUP)
740         HandleSetupScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
741       break;
742     }
743
744     case HALLOFFAME:
745       HandleHallOfFame(!newbutton);
746       break;
747
748     case HELPSCREEN:
749       HandleHelpScreen(!newbutton);
750       break;
751
752     case PLAYING:
753       if (tape.playing || keyboard)
754         newbutton = ((joy & JOY_BUTTON) != 0);
755
756       if (AllPlayersGone && newbutton)
757       {
758         CloseDoor(DOOR_CLOSE_1);
759         game_status = MAINMENU;
760         DrawMainMenu();
761         return;
762       }
763
764       if (tape.pausing || AllPlayersGone)
765         joy = 0;
766
767       HandleGameActions(joy);
768       break;
769
770     default:
771       break;
772   }
773 }