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