Repository: missionpinball/mpf

Issue:
Support game start/player add with an event in attract and game mode
Currently we only support switches to start a game. Also allow event only starts (e.g. with combo_switches). See: https://groups.google.com/forum/#!topic/mpf-users/vuUJMdSI2_A

Discussion:

Patch:
diff --git a/mpf/config_spec.yaml b/mpf/config_spec.yaml
index 937b708c5..39c05c8eb 100644
--- a/mpf/config_spec.yaml
+++ b/mpf/config_spec.yaml
@@ -544,7 +544,9 @@ game:
     balls_per_game: single|template_int|3
     max_players: single|template_int|4
     start_game_switch_tag: single|str|start
+    start_game_event: single|str|None
     add_player_switch_tag: single|str|start
+    add_player_event: single|str|None
     allow_start_with_loose_balls: single|bool|False
     allow_start_with_ball_in_drain: single|bool|False
 hardware:
diff --git a/mpf/modes/attract/code/attract.py b/mpf/modes/attract/code/attract.py
index 365d7e1c7..1a933ac27 100644
--- a/mpf/modes/attract/code/attract.py
+++ b/mpf/modes/attract/code/attract.py
@@ -38,6 +38,9 @@ class Attract(Mode):
                 self.machine.switch_controller.add_switch_handler(
                     switch.name, self.start_button_released, 0))
 
+        if self.machine.config['game']['start_game_event']:
+            self.add_mode_event_handler(self.machine.config['game']['start_game_event'], self.start_button_released)
+
         if hasattr(self.machine, 'ball_devices'):
             self.machine.ball_controller.collect_balls()
 
@@ -61,7 +64,7 @@ class Attract(Mode):
         """
         self.start_button_pressed_time = self.machine.clock.get_time()
 
-    def start_button_released(self):
+    def start_button_released(self, **kwargs):
         """Handle start button release.
 
         Called when the a switch tagged with *start* is deactivated.
@@ -70,6 +73,7 @@ class Attract(Mode):
         called *request_to_start_game*. If that event comes back True, this
         method calls :meth:`result_of_start_request`.
         """
+        del kwargs
         self.start_hold_time = self.machine.clock.get_time() - self.start_button_pressed_time
         self.start_buttons_held = list()
 
diff --git a/mpf/modes/game/code/game.py b/mpf/modes/game/code/game.py
index 663774e91..a4b548115 100644
--- a/mpf/modes/game/code/game.py
+++ b/mpf/modes/game/code/game.py
@@ -73,6 +73,9 @@ class Game(AsyncMode):
                     '%', self.machine.config['game']['add_player_switch_tag']),
                 self.request_player_add)
 
+        if self.machine.config['game']['add_player_event']:
+            self.add_mode_event_handler(self.machine.config['game']['add_player_event'], self.request_player_add)
+
         self.max_players = self.machine.config['game']['max_players'].evaluate({})
 
         yield from self._start_game()


Test patch:
diff --git a/mpf/tests/machine_files/game/config/config.yaml b/mpf/tests/machine_files/game/config/config.yaml
index c43ae23eb..d8aa231d6 100644
--- a/mpf/tests/machine_files/game/config/config.yaml
+++ b/mpf/tests/machine_files/game/config/config.yaml
@@ -2,6 +2,8 @@
 
 game:
     balls_per_game: 3
+    start_game_event: start_my_game
+    add_player_event: add_my_player
 
 coils:
     eject_coil1:
diff --git a/mpf/tests/test_Game.py b/mpf/tests/test_Game.py
index 65064903f..9b6483c7d 100644
--- a/mpf/tests/test_Game.py
+++ b/mpf/tests/test_Game.py
@@ -388,6 +388,29 @@ class TestGame(MpfGameTestCase):
         self.assertEqual('game_ending', self._events.call_args_list[7][1]['event_name'])
         self.assertEqual('game_ended', self._events.call_args_list[8][1]['event_name'])
 
+    def testGameEvents(self):
+        self.machine.switch_controller.process_switch('s_ball_switch1', 1)
+        self.machine.switch_controller.process_switch('s_ball_switch2', 1)
+        self.advance_time_and_run(10)
+        self.assertEqual(2, self.machine.ball_controller.num_balls_known)
+        self.assertEqual(2, self.machine.ball_devices.bd_trough.balls)
+
+        self.post_event("start_my_game")
+        self.assertGameIsRunning()
+        self.advance_time_and_run()
+        self.assertPlayerCount(1)
+        self.post_event("start_my_game")
+        self.assertPlayerCount(1)
+
+        self.post_event("add_my_player")
+        self.assertPlayerCount(2)
+        self.post_event("add_my_player")
+        self.assertPlayerCount(3)
+        self.post_event("add_my_player")
+        self.assertPlayerCount(4)
+        self.post_event("add_my_player")
+        self.assertPlayerCount(4)
+
 
 class TestGameLogic(MpfFakeGameTestCase):