moved code for fixing single-player tapes to separate function
[rocksndiamonds.git] / src / events.c
index 32f7177964af22b746b8c6727cd23d207f96a5da..2df4eb7bc3a3a4320f6ed4a36b79419b6e06e093 100644 (file)
@@ -4,7 +4,7 @@
 // (c) 1995-2014 by Artsoft Entertainment
 //                         Holger Schemel
 //                 info@artsoft.org
-//                 http://www.artsoft.org/
+//                 https://www.artsoft.org/
 // ----------------------------------------------------------------------------
 // events.c
 // ============================================================================
@@ -94,6 +94,25 @@ static int FilterEvents(const Event *event)
     ((MotionEvent *)event)->y -= video.screen_yoffset;
   }
 
+  if (event->type == EVENT_BUTTONPRESS ||
+      event->type == EVENT_BUTTONRELEASE ||
+      event->type == EVENT_MOTIONNOTIFY)
+  {
+    // do not reset mouse cursor before all pending events have been processed
+    if (gfx.cursor_mode == cursor_mode_last &&
+       ((game_status == GAME_MODE_TITLE &&
+         gfx.cursor_mode == CURSOR_NONE) ||
+        (game_status == GAME_MODE_PLAYING &&
+         gfx.cursor_mode == CURSOR_PLAYFIELD)))
+    {
+      SetMouseCursor(CURSOR_DEFAULT);
+
+      DelayReached(&special_cursor_delay, 0);
+
+      cursor_mode_last = CURSOR_DEFAULT;
+    }
+  }
+
   // non-motion events are directly passed to event handler functions
   if (event->type != EVENT_MOTIONNOTIFY)
     return 1;
@@ -111,20 +130,6 @@ static int FilterEvents(const Event *event)
   gfx.mouse_x = motion->x;
   gfx.mouse_y = motion->y;
 
-  // do no reset mouse cursor before all pending events have been processed
-  if (gfx.cursor_mode == cursor_mode_last &&
-      ((game_status == GAME_MODE_TITLE &&
-       gfx.cursor_mode == CURSOR_NONE) ||
-       (game_status == GAME_MODE_PLAYING &&
-       gfx.cursor_mode == CURSOR_PLAYFIELD)))
-  {
-    SetMouseCursor(CURSOR_DEFAULT);
-
-    DelayReached(&special_cursor_delay, 0);
-
-    cursor_mode_last = CURSOR_DEFAULT;
-  }
-
   // skip mouse motion events without pressed button outside level editor
   if (button_status == MB_RELEASED &&
       game_status != GAME_MODE_EDITOR && game_status != GAME_MODE_PLAYING)
@@ -322,6 +327,10 @@ static void HandleMouseCursor(void)
   {
     // when playing, display a special mouse pointer inside the playfield
 
+    // display normal pointer if mouse pressed
+    if (button_status != MB_RELEASED)
+      DelayReached(&special_cursor_delay, 0);
+
     if (gfx.cursor_mode != CURSOR_PLAYFIELD &&
        cursor_inside_playfield &&
        DelayReached(&special_cursor_delay, special_cursor_delay_value))
@@ -455,7 +464,7 @@ static void SetPlayerMouseAction(int mx, int my, int button)
   local_player->mouse_action.ly = ly;
   local_player->mouse_action.button = button;
 
-  if (tape.recording && tape.pausing && tape.use_mouse)
+  if (tape.recording && tape.pausing && tape.use_mouse_actions)
   {
     // un-pause a paused game only if mouse button was newly pressed down
     if (new_button)
@@ -1275,7 +1284,7 @@ static void HandleButtonOrFinger_FollowFinger(int mx, int my, int button)
       int last_move_dir = (ABS(dx) > ABS(dy) ? MV_VERTICAL : MV_HORIZONTAL);
 
       if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
-       level.native_em_level->ply[0]->last_move_dir = last_move_dir;
+       game_em.ply[0]->last_move_dir = last_move_dir;
       else
        local_player->last_move_dir = last_move_dir;
 
@@ -1348,6 +1357,8 @@ static void HandleButtonOrFinger_FollowFinger(int mx, int my, int button)
 
 static void HandleButtonOrFinger(int mx, int my, int button)
 {
+  boolean valid_mouse_event = (mx != -1 && my != -1 && button != -1);
+
   if (game_status != GAME_MODE_PLAYING)
     return;
 
@@ -1364,16 +1375,19 @@ static void HandleButtonOrFinger(int mx, int my, int button)
   {
     if (strEqual(setup.touch.control_type, TOUCH_CONTROL_FOLLOW_FINGER))
       HandleButtonOrFinger_FollowFinger(mx, my, button);
+    else if (game.use_mouse_actions && valid_mouse_event)
+      SetPlayerMouseAction(mx, my, button);
   }
 }
 
-static boolean checkTextInputKeyModState(void)
+static boolean checkTextInputKey(Key key)
 {
   // when playing, only handle raw key events and ignore text input
   if (game_status == GAME_MODE_PLAYING)
     return FALSE;
 
-  return ((GetKeyModState() & KMOD_TextInput) != KMOD_None);
+  // else handle all printable keys as text input
+  return KSYM_PRINTABLE(key);
 }
 
 void HandleTextEvent(TextEvent *event)
@@ -1391,16 +1405,12 @@ void HandleTextEvent(TextEvent *event)
        GetKeyModState());
 #endif
 
-#if !defined(HAS_SCREEN_KEYBOARD)
-  // non-mobile devices: only handle key input with modifier keys pressed here
-  // (every other key input is handled directly as physical key input event)
-  if (!checkTextInputKeyModState())
-    return;
-#endif
-
-  // process text input as "classic" (with uppercase etc.) key input event
-  HandleKey(key, KEY_PRESSED);
-  HandleKey(key, KEY_RELEASED);
+  if (checkTextInputKey(key))
+  {
+    // process printable keys (with uppercase etc.) in text input mode
+    HandleKey(key, KEY_PRESSED);
+    HandleKey(key, KEY_RELEASED);
+  }
 }
 
 void HandlePauseResumeEvent(PauseResumeEvent *event)
@@ -1449,13 +1459,16 @@ void HandleKeyEvent(KeyEvent *event)
   {
     // for any other "real" key event, disable virtual buttons
     SetOverlayEnabled(FALSE);
+
+    // for any other "real" key event, disable overlay touch buttons
+    runtime.uses_touch_device = FALSE;
   }
 #endif
 
   HandleKeyModState(keymod, key_status);
 
-  // only handle raw key input without text modifier keys pressed
-  if (!checkTextInputKeyModState())
+  // process all keys if not in text input mode or if non-printable keys
+  if (!checkTextInputKey(key))
     HandleKey(key, key_status);
 }
 
@@ -1767,17 +1780,6 @@ void HandleButton(int mx, int my, int button, int button_nr)
   }
 }
 
-static boolean is_string_suffix(char *string, char *suffix)
-{
-  int string_len = strlen(string);
-  int suffix_len = strlen(suffix);
-
-  if (suffix_len > string_len)
-    return FALSE;
-
-  return (strEqual(&string[string_len - suffix_len], suffix));
-}
-
 #define MAX_CHEAT_INPUT_LEN    32
 
 static void HandleKeysSpecial(Key key)
@@ -1807,73 +1809,64 @@ static void HandleKeysSpecial(Key key)
 
   if (game_status == GAME_MODE_MAIN)
   {
-    if (is_string_suffix(cheat_input, ":insert-solution-tape") ||
-       is_string_suffix(cheat_input, ":ist"))
+    if (strSuffix(cheat_input, ":insert-solution-tape") ||
+       strSuffix(cheat_input, ":ist"))
     {
       InsertSolutionTape();
     }
-    else if (is_string_suffix(cheat_input, ":play-solution-tape") ||
-            is_string_suffix(cheat_input, ":pst"))
+    else if (strSuffix(cheat_input, ":play-solution-tape") ||
+            strSuffix(cheat_input, ":pst"))
     {
       PlaySolutionTape();
     }
-    else if (is_string_suffix(cheat_input, ":reload-graphics") ||
-            is_string_suffix(cheat_input, ":rg"))
+    else if (strSuffix(cheat_input, ":reload-graphics") ||
+            strSuffix(cheat_input, ":rg"))
     {
       ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS);
       DrawMainMenu();
     }
-    else if (is_string_suffix(cheat_input, ":reload-sounds") ||
-            is_string_suffix(cheat_input, ":rs"))
+    else if (strSuffix(cheat_input, ":reload-sounds") ||
+            strSuffix(cheat_input, ":rs"))
     {
       ReloadCustomArtwork(1 << ARTWORK_TYPE_SOUNDS);
       DrawMainMenu();
     }
-    else if (is_string_suffix(cheat_input, ":reload-music") ||
-            is_string_suffix(cheat_input, ":rm"))
+    else if (strSuffix(cheat_input, ":reload-music") ||
+            strSuffix(cheat_input, ":rm"))
     {
       ReloadCustomArtwork(1 << ARTWORK_TYPE_MUSIC);
       DrawMainMenu();
     }
-    else if (is_string_suffix(cheat_input, ":reload-artwork") ||
-            is_string_suffix(cheat_input, ":ra"))
+    else if (strSuffix(cheat_input, ":reload-artwork") ||
+            strSuffix(cheat_input, ":ra"))
     {
       ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS |
                          1 << ARTWORK_TYPE_SOUNDS |
                          1 << ARTWORK_TYPE_MUSIC);
       DrawMainMenu();
     }
-    else if (is_string_suffix(cheat_input, ":dump-level") ||
-            is_string_suffix(cheat_input, ":dl"))
+    else if (strSuffix(cheat_input, ":dump-level") ||
+            strSuffix(cheat_input, ":dl"))
     {
       DumpLevel(&level);
     }
-    else if (is_string_suffix(cheat_input, ":dump-tape") ||
-            is_string_suffix(cheat_input, ":dt"))
+    else if (strSuffix(cheat_input, ":dump-tape") ||
+            strSuffix(cheat_input, ":dt"))
     {
       DumpTape(&tape);
     }
-    else if (is_string_suffix(cheat_input, ":fix-tape") ||
-            is_string_suffix(cheat_input, ":ft"))
+    else if (strSuffix(cheat_input, ":fix-tape") ||
+            strSuffix(cheat_input, ":ft"))
     {
-      /* fix single-player tapes that contain player input for more than one
-        player (due to a bug in 3.3.1.2 and earlier versions), which results
-        in playing levels with more than one player in multi-player mode,
-        even though the tape was originally recorded in single-player mode */
-
-      // remove player input actions for all players but the first one
-      for (i = 1; i < MAX_PLAYERS; i++)
-       tape.player_participates[i] = FALSE;
-
-      tape.changed = TRUE;
+      FixTape_ForceSinglePlayer();
     }
-    else if (is_string_suffix(cheat_input, ":save-native-level") ||
-            is_string_suffix(cheat_input, ":snl"))
+    else if (strSuffix(cheat_input, ":save-native-level") ||
+            strSuffix(cheat_input, ":snl"))
     {
       SaveNativeLevel(&level);
     }
-    else if (is_string_suffix(cheat_input, ":frames-per-second") ||
-            is_string_suffix(cheat_input, ":fps"))
+    else if (strSuffix(cheat_input, ":frames-per-second") ||
+            strSuffix(cheat_input, ":fps"))
     {
       global.show_frames_per_second = !global.show_frames_per_second;
     }
@@ -1881,18 +1874,18 @@ static void HandleKeysSpecial(Key key)
   else if (game_status == GAME_MODE_PLAYING)
   {
 #ifdef DEBUG
-    if (is_string_suffix(cheat_input, ".q"))
+    if (strSuffix(cheat_input, ".q"))
       DEBUG_SetMaximumDynamite();
 #endif
   }
   else if (game_status == GAME_MODE_EDITOR)
   {
-    if (is_string_suffix(cheat_input, ":dump-brush") ||
-       is_string_suffix(cheat_input, ":DB"))
+    if (strSuffix(cheat_input, ":dump-brush") ||
+       strSuffix(cheat_input, ":DB"))
     {
       DumpBrush();
     }
-    else if (is_string_suffix(cheat_input, ":DDB"))
+    else if (strSuffix(cheat_input, ":DDB"))
     {
       DumpBrush_Small();
     }
@@ -1922,9 +1915,9 @@ static void HandleKeysSpecial(Key key)
   }
 
   // special key shortcuts for all game modes
-  if (is_string_suffix(cheat_input, ":dump-event-actions") ||
-      is_string_suffix(cheat_input, ":dea") ||
-      is_string_suffix(cheat_input, ":DEA"))
+  if (strSuffix(cheat_input, ":dump-event-actions") ||
+      strSuffix(cheat_input, ":dea") ||
+      strSuffix(cheat_input, ":DEA"))
   {
     DumpGadgetIdentifiers();
     DumpScreenIdentifiers();
@@ -2082,43 +2075,46 @@ void HandleKey(Key key, int key_status)
       if (stored_player[pnr].snap_action)
        stored_player[pnr].action |= JOY_BUTTON_SNAP;
 
-      if (tape.single_step && tape.recording && tape.pausing && !tape.use_mouse)
+      if (tape.recording && tape.pausing && tape.use_key_actions)
       {
-       if (key_status == KEY_PRESSED && key_action & KEY_MOTION)
+       if (tape.single_step)
        {
-         TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
+         if (key_status == KEY_PRESSED && key_action & KEY_MOTION)
+         {
+           TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
 
-         // if snap key already pressed, keep pause mode when releasing
-         if (stored_player[pnr].action & KEY_BUTTON_SNAP)
-           has_snapped[pnr] = TRUE;
-       }
-       else if (key_status == KEY_PRESSED && key_action & KEY_BUTTON_DROP)
-       {
-         TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
+           // if snap key already pressed, keep pause mode when releasing
+           if (stored_player[pnr].action & KEY_BUTTON_SNAP)
+             has_snapped[pnr] = TRUE;
+         }
+         else if (key_status == KEY_PRESSED && key_action & KEY_BUTTON_DROP)
+         {
+           TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
 
-         if (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
-             getRedDiskReleaseFlag_SP() == 0)
+           if (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
+               getRedDiskReleaseFlag_SP() == 0)
+           {
+             // add a single inactive frame before dropping starts
+             stored_player[pnr].action &= ~KEY_BUTTON_DROP;
+             stored_player[pnr].force_dropping = TRUE;
+           }
+         }
+         else if (key_status == KEY_RELEASED && key_action & KEY_BUTTON_SNAP)
          {
-           // add a single inactive frame before dropping starts
-           stored_player[pnr].action &= ~KEY_BUTTON_DROP;
-           stored_player[pnr].force_dropping = TRUE;
+           // if snap key was pressed without direction, leave pause mode
+           if (!has_snapped[pnr])
+             TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
+
+           has_snapped[pnr] = FALSE;
          }
        }
-       else if (key_status == KEY_RELEASED && key_action & KEY_BUTTON_SNAP)
+       else
        {
-         // if snap key was pressed without direction, leave pause mode
-         if (!has_snapped[pnr])
-           TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
-
-         has_snapped[pnr] = FALSE;
+         // prevent key release events from un-pausing a paused game
+         if (key_status == KEY_PRESSED && key_action & KEY_ACTION)
+           TapeTogglePause(TAPE_TOGGLE_MANUAL);
        }
       }
-      else if (tape.recording && tape.pausing && !tape.use_mouse)
-      {
-       // prevent key release events from un-pausing a paused game
-       if (key_status == KEY_PRESSED && key_action & KEY_ACTION)
-         TapeTogglePause(TAPE_TOGGLE_MANUAL);
-      }
 
       // for MM style levels, handle in-game keyboard input in HandleJoystick()
       if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
@@ -2161,7 +2157,7 @@ void HandleKey(Key key, int key_status)
   {
     setup.fullscreen = !setup.fullscreen;
 
-    ToggleFullscreenOrChangeWindowScalingIfNeeded();
+    ToggleFullscreenIfNeeded();
 
     if (game_status == GAME_MODE_SETUP)
       RedrawSetupScreenAfterFullscreenToggle();
@@ -2194,7 +2190,7 @@ void HandleKey(Key key, int key_status)
     else if (setup.window_scaling_percent > MAX_WINDOW_SCALING_PERCENT)
       setup.window_scaling_percent = MAX_WINDOW_SCALING_PERCENT;
 
-    ToggleFullscreenOrChangeWindowScalingIfNeeded();
+    ChangeWindowScalingIfNeeded();
 
     if (game_status == GAME_MODE_SETUP)
       RedrawSetupScreenAfterFullscreenToggle();
@@ -2614,15 +2610,18 @@ void HandleJoystick(void)
        return;
       }
 
-      if (tape.single_step && tape.recording && tape.pausing && !tape.use_mouse)
-      {
-       if (joystick & JOY_ACTION)
-         TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
-      }
-      else if (tape.recording && tape.pausing && !tape.use_mouse)
+      if (tape.recording && tape.pausing && tape.use_key_actions)
       {
-       if (joystick & JOY_ACTION)
-         TapeTogglePause(TAPE_TOGGLE_MANUAL);
+       if (tape.single_step)
+       {
+         if (joystick & JOY_ACTION)
+           TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
+       }
+       else
+       {
+         if (joystick & JOY_ACTION)
+           TapeTogglePause(TAPE_TOGGLE_MANUAL);
+       }
       }
 
       if (level.game_engine_type == GAME_ENGINE_TYPE_MM)