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