ff86409e640952345561ebeacf78ece8163d1eb3
[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 += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
184     fy += (ScreenMovDir & (MV_UP|MV_DOWN)    ? ScreenGfxPos : 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_VIS_FIELD(sx,sy))
277     {
278       int x = LEVELX(sx);
279       int y = LEVELY(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("      MovPos[%d][%d] == %d\n", x,y, MovPos[x][y]);
286       printf("      MovDir[%d][%d] == %d\n", x,y, MovDir[x][y]);
287       printf("      MovDelay[%d][%d] == %d\n", x,y, MovDelay[x][y]);
288       printf("\n");
289     }
290   }
291 #endif
292
293   switch(game_status)
294   {
295     case MAINMENU:
296       HandleMainMenu(mx,my,0,0,button);
297       break;
298     case TYPENAME:
299       HandleTypeName(0,XK_Return);
300       break;
301     case CHOOSELEVEL:
302       HandleChooseLevel(mx,my,0,0,button);
303       break;
304     case HALLOFFAME:
305       HandleHallOfFame(button);
306       break;
307     case LEVELED:
308       LevelEd(mx,my,button);
309       break;
310     case HELPSCREEN:
311       HandleHelpScreen(button);
312       break;
313     case SETUP:
314       HandleSetupScreen(mx,my,0,0,button);
315       break;
316     case PLAYING:
317       HandleGameActions(0);
318       break;
319     default:
320       break;
321   }
322 }
323
324 void HandleKey(KeySym key, int key_status)
325 {
326   int joy = 0;
327
328   /* Map cursor keys to joystick directions */
329
330   switch(key)
331   {
332     case XK_Left:               /* normale Richtungen */
333 #ifdef XK_KP_Left
334     case XK_KP_Left:
335 #endif
336     case XK_KP_4:
337 #ifndef MSDOS
338     case XK_J:
339 #endif
340     case XK_j:
341       joy |= JOY_LEFT;
342       break;
343     case XK_Right:
344 #ifdef XK_KP_Right
345     case XK_KP_Right:
346 #endif
347     case XK_KP_6:
348 #ifndef MSDOS
349     case XK_K:
350 #endif
351     case XK_k:
352       joy |= JOY_RIGHT;
353       break;
354     case XK_Up:
355 #ifdef XK_KP_Up
356     case XK_KP_Up:
357 #endif
358     case XK_KP_8:
359 #ifndef MSDOS
360     case XK_I:
361 #endif
362     case XK_i:
363       joy |= JOY_UP;
364       break;
365     case XK_Down:
366 #ifdef XK_KP_Down
367     case XK_KP_Down:
368 #endif
369     case XK_KP_2:
370 #ifndef MSDOS
371     case XK_M:
372 #endif
373     case XK_m:
374       joy |= JOY_DOWN;
375       break;
376 #ifdef XK_KP_Home
377     case XK_KP_Home:            /* Diagonalrichtungen */
378 #endif
379     case XK_KP_7:
380       joy |= JOY_UP | JOY_LEFT;
381       break;
382 #ifdef XK_KP_Page_Up
383     case XK_KP_Page_Up:
384 #endif
385     case XK_KP_9:
386       joy = JOY_UP | JOY_RIGHT;
387       break;
388 #ifdef XK_KP_End
389     case XK_KP_End:
390 #endif
391     case XK_KP_1:
392       joy |= JOY_DOWN | JOY_LEFT;
393       break;
394 #ifdef XK_KP_Page_Down
395     case XK_KP_Page_Down:
396 #endif
397     case XK_KP_3:
398       joy |= JOY_DOWN | JOY_RIGHT;
399       break;
400 #ifndef MSDOS
401     case XK_S:                  /* Feld entfernen */
402 #endif
403     case XK_s:
404       joy |= JOY_BUTTON_1 | JOY_LEFT;
405       break;
406 #ifndef MSDOS
407     case XK_D:
408 #endif
409     case XK_d:
410       joy |= JOY_BUTTON_1 | JOY_RIGHT;
411       break;
412 #ifndef MSDOS
413     case XK_E:
414 #endif
415     case XK_e:
416       joy |= JOY_BUTTON_1 | JOY_UP;
417       break;
418 #ifndef MSDOS
419     case XK_X:
420 #endif
421     case XK_x:
422       joy |= JOY_BUTTON_1 | JOY_DOWN;
423       break;
424     case XK_Shift_L:            /* Linker Feuerknopf */
425 #ifndef MSDOS
426     case XK_Control_L:
427     case XK_Alt_L:
428     case XK_Meta_L:
429 #endif
430       joy |= JOY_BUTTON_1;
431       break;
432     case XK_Shift_R:            /* Rechter Feuerknopf */
433 #ifndef MSDOS
434     case XK_Control_R:
435     case XK_Alt_R:
436     case XK_Meta_R:
437     case XK_Mode_switch:
438     case XK_Multi_key:
439     case XK_B:                  /* (Bombe legen) */
440 #endif
441     case XK_b:
442       joy |= JOY_BUTTON_2;
443       break;
444     default:
445       break;
446   }
447
448   if (joy)
449   {
450     if (key_status == KEY_PRESSED)
451       key_joystick_mapping |= joy;
452     else
453       key_joystick_mapping &= ~joy;
454
455     HandleJoystick();
456   }
457
458   if (game_status != PLAYING)
459     key_joystick_mapping = 0;
460
461   if (key_status == KEY_RELEASED)
462     return;
463
464   if (key==XK_Return && game_status==PLAYING && AllPlayersGone)
465   {
466     CloseDoor(DOOR_CLOSE_1);
467     game_status = MAINMENU;
468     DrawMainMenu();
469     return;
470   }
471
472   if (key==XK_Escape && game_status!=MAINMENU)  /* quick quit to MAINMENU */
473   {
474     CloseDoor(DOOR_CLOSE_1 | DOOR_NO_DELAY);
475     game_status = MAINMENU;
476     DrawMainMenu();
477     return;
478   }
479
480   if (game_status==PLAYING && (tape.playing || tape.pausing))
481     return;
482
483   switch(game_status)
484   {
485     case TYPENAME:
486       HandleTypeName(0,key);
487       break;
488     case MAINMENU:
489     case CHOOSELEVEL:
490     case SETUP:
491     {
492       switch(key)
493       {
494         case XK_Return:
495           if (game_status==MAINMENU)
496             HandleMainMenu(0,0,0,0,MB_MENU_CHOICE);
497           else if (game_status==CHOOSELEVEL)
498             HandleChooseLevel(0,0,0,0,MB_MENU_CHOICE);
499           else if (game_status==SETUP)
500             HandleSetupScreen(0,0,0,0,MB_MENU_CHOICE);
501           break;
502         default:
503           break;
504       }
505       break;
506     }
507     case HELPSCREEN:
508       HandleHelpScreen(MB_RELEASED);
509       break;
510     case HALLOFFAME:
511       switch(key)
512       {
513         case XK_Return:
514           game_status = MAINMENU;
515           DrawMainMenu();
516           BackToFront();
517           break;
518         default:
519           break;
520       }
521       break;
522     case LEVELED:
523       LevelNameTyping(key);
524       break;
525     case PLAYING:
526     {
527       switch(key)
528       {
529
530 #ifdef DEBUG
531         case XK_0:
532         case XK_1:
533         case XK_2:
534         case XK_3:
535         case XK_4:
536         case XK_5:
537         case XK_6:
538         case XK_7:
539         case XK_8:
540         case XK_9:
541           if (key == XK_0)
542             GameFrameDelay = 500;
543           else
544             GameFrameDelay = (key - XK_0) * 10;
545           printf("Game speed == %d%% (%d ms delay between two frames)\n",
546                  GAME_FRAME_DELAY * 100 / GameFrameDelay, GameFrameDelay);
547           break;
548
549         case XK_a:
550           if (ScrollStepSize == TILEX/8)
551             ScrollStepSize = TILEX/4;
552           else
553             ScrollStepSize = TILEX/8;
554           printf("ScrollStepSize == %d\n", ScrollStepSize);
555           break;
556
557         case XK_f:
558           ScrollStepSize = TILEX/8;
559           printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
560           break;
561         case XK_g:
562           ScrollStepSize = TILEX/4;
563           printf("ScrollStepSize == %d (1/4)\n", ScrollStepSize);
564           break;
565         case XK_h:
566           ScrollStepSize = TILEX/2;
567           printf("ScrollStepSize == %d (1/2)\n", ScrollStepSize);
568           break;
569         case XK_l:
570           ScrollStepSize = TILEX;
571           printf("ScrollStepSize == %d (1/1)\n", ScrollStepSize);
572           break;
573
574 #ifndef MSDOS
575         case XK_Q:
576 #endif
577         case XK_q:
578           local_player->dynamite = 1000;
579           break;
580
581         case XK_x:
582
583           {
584             int i,j,k, num_steps = 8, step_size = TILEX / num_steps;
585             static long scroll_delay=0;
586             long scroll_delay_value = 4*4 / num_steps;
587
588             printf("Scroll test\n");
589
590             for(i=0;i<3;i++)
591             {
592               for(j=0;j<SCR_FIELDX;j++)
593               {
594                 for(k=0;k<num_steps;k++)
595                 {
596                   int xxx = j*TILEX+k*step_size;
597                   int done = 0;
598
599                   while(!done)
600                   {
601                     if (DelayReached(&scroll_delay, scroll_delay_value))
602                     {
603                       XCopyArea(display,fieldbuffer,window,gc,
604                                 SX+xxx,SY,
605                                 SXSIZE-xxx,SYSIZE,
606                                 SX,SY);
607                       XCopyArea(display,fieldbuffer,window,gc,
608                                 SX,SY,
609                                 xxx,SYSIZE,
610                                 SX+SXSIZE-xxx,SY);
611   
612                       XFlush(display);
613                       XSync(display,FALSE);
614
615                       done = 1;
616                     }
617                     else
618                     {
619                       Delay(1);
620                     }
621                   }
622   
623                   /*
624                   Delay(160 / num_steps);
625                   */
626                   /*
627                   Delay(120 / num_steps);
628                   */
629                 }
630               }
631             }
632           }
633
634           break;
635
636         case XK_y:
637           /*
638           {
639             printf("FX = %d, FY = %d\n", FX,FY);
640
641             XCopyArea(display,fieldbuffer,window,gc,
642                       0,0,
643                       MIN(WIN_XSIZE,FXSIZE),MIN(WIN_YSIZE,FYSIZE),
644                       0,0);
645             XFlush(display);
646             XSync(display,FALSE);
647             Delay(1000);
648           }
649           */
650
651           printf("direct_draw_on == %d\n", direct_draw_on);
652
653           break;
654
655         case XK_z:
656           {
657             int i;
658
659             for(i=0; i<MAX_PLAYERS; i++)
660             {
661               printf("Player %d:\n", i);
662               printf("  jx == %d, jy == %d\n",
663                      stored_player[i].jx, stored_player[i].jy);
664               printf("  last_jx == %d, last_jy == %d\n",
665                      stored_player[i].last_jx, stored_player[i].last_jy);
666             }
667             printf("\n");
668           }
669
670           break;
671
672         case XK_t:
673           {
674             char *color[] = { "yellow", "red", "green", "blue" };
675
676             do
677               TestPlayer = (TestPlayer + 1) % MAX_PLAYERS;
678             while(!stored_player[TestPlayer].active);
679
680             printf("TestPlayer = %d (%s player)\n",
681                    TestPlayer, color[TestPlayer]);
682           }
683
684           break;
685 #endif
686
687         default:
688           break;
689       }
690       break;
691     }
692     default:
693       break;
694   }
695 }
696
697 void HandleNoXEvent()
698 {
699   if (button_status && game_status != PLAYING)
700   {
701     HandleButton(-1,-1,button_status);
702     return;
703   }
704
705   switch(game_status)
706   {
707     case MAINMENU:
708     case CHOOSELEVEL:
709     case HALLOFFAME:
710     case HELPSCREEN:
711     case SETUP:
712       HandleJoystick();
713       break;
714     case PLAYING:
715       HandleJoystick();
716
717       /*
718       HandleGameActions(0);
719       */
720
721       break;
722     default:
723       break;
724   }
725 }
726
727 void HandleJoystick()
728 {
729   int joystick  = Joystick();
730   int keyboard  = key_joystick_mapping;
731
732   /*
733   int joy       = (tape.playing ? TapePlayAction() : (joystick | keyboard));
734   */
735
736   int joy       = (joystick | keyboard);
737   int left      = joy & JOY_LEFT;
738   int right     = joy & JOY_RIGHT;
739   int up        = joy & JOY_UP;
740   int down      = joy & JOY_DOWN;
741   int button    = joy & JOY_BUTTON;
742   int newbutton = (JoystickButton() == JOY_BUTTON_NEW_PRESSED);
743   int dx        = (left ? -1    : right ? 1     : 0);
744   int dy        = (up   ? -1    : down  ? 1     : 0);
745
746   switch(game_status)
747   {
748     case MAINMENU:
749     case CHOOSELEVEL:
750     case SETUP:
751     {
752       static long joystickmove_delay = 0;
753
754       if (joystick && !button && !DelayReached(&joystickmove_delay,15))
755         newbutton = dx = dy = 0;
756
757       if (game_status==MAINMENU)
758         HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
759       else if (game_status==CHOOSELEVEL)
760         HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
761       else if (game_status==SETUP)
762         HandleSetupScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
763       break;
764     }
765
766     case HALLOFFAME:
767       HandleHallOfFame(!newbutton);
768       break;
769
770     case HELPSCREEN:
771       HandleHelpScreen(!newbutton);
772       break;
773
774     case PLAYING:
775       if (tape.playing || keyboard)
776         newbutton = ((joy & JOY_BUTTON) != 0);
777
778       if (AllPlayersGone && newbutton)
779       {
780         CloseDoor(DOOR_CLOSE_1);
781         game_status = MAINMENU;
782         DrawMainMenu();
783         return;
784       }
785
786       if (tape.pausing || AllPlayersGone)
787         joy = 0;
788
789       HandleGameActions(joy);
790       break;
791
792     default:
793       break;
794   }
795 }