From b6d04da772205b0af9721fe5de2ff91b5fa0c1de Mon Sep 17 00:00:00 2001 From: Avery Tummons Date: Sun, 1 Aug 2021 20:07:09 -0500 Subject: [PATCH 1/9] Adds additional ball save features to multiballs Added hurry up and grace period features to the multiball ball save. This allows the user to run shows off the hurry up, as well as provide a grace period for saves. --- mpf/config_spec.yaml | 7 ++- mpf/devices/multiball.py | 59 ++++++++++++++++--- .../multiball/config/config.yaml | 9 ++- mpf/tests/test_MultiBall.py | 52 ++++++++++++++++ 4 files changed, 117 insertions(+), 10 deletions(-) diff --git a/mpf/config_spec.yaml b/mpf/config_spec.yaml index b15af7845..eba776b95 100644 --- a/mpf/config_spec.yaml +++ b/mpf/config_spec.yaml @@ -971,7 +971,9 @@ multiballs: ball_count_type: single|enum(add,total)|total replace_balls_in_play: single|bool|false source_playfield: single|machine(ball_devices)|playfield - shoot_again: single|template_ms|10s + shoot_again: single|template_secs|10s + hurry_up_time: single|template_secs|0 + grace_period: single|template_secs|0 ball_locks: list|machine(ball_devices)|None enable_events: event_handler|event_handler:ms|None disable_events: event_handler|event_handler:ms|None @@ -979,6 +981,9 @@ multiballs: start_events: event_handler|event_handler:ms|None stop_events: event_handler|event_handler:ms|None add_a_ball_events: event_handler|event_handler:ms|None + add_a_ball_shoot_again: single|template_secs|3s + add_a_ball_hurry_up_time: single|ms|0 + add_a_ball_grace_period: single|ms|0 start_or_add_a_ball_events: event_handler|event_handler:ms|None multiball_locks: __valid_in__: mode diff --git a/mpf/devices/multiball.py b/mpf/devices/multiball.py index 9b0acfd14..75c7abb06 100644 --- a/mpf/devices/multiball.py +++ b/mpf/devices/multiball.py @@ -124,7 +124,7 @@ def start(self): if self.balls_added_live - balls_added > 0: self.source_playfield.add_ball(balls=self.balls_added_live - balls_added) - shoot_again_ms = self.config['shoot_again'].evaluate([]) + shoot_again_ms = self.config['shoot_again'].evaluate([]) * 1000 if not shoot_again_ms: # No shoot again. Just stop multiball right away self.stop() @@ -133,11 +133,7 @@ def start(self): self.machine.events.add_handler('ball_drain', self._ball_drain_shoot_again, priority=1000) - # Register stop handler - if shoot_again_ms > 0: - self.delay.add(name='disable_shoot_again', - ms=shoot_again_ms, - callback=self.stop) + self.timer_start() self.machine.events.post("multiball_" + self.name + "_started", balls=self.balls_live_target) @@ -147,6 +143,53 @@ def start(self): balls: The number of balls in this multiball ''' + def timer_start(self) -> None: + """Start the timer. + + This is started when multiball starts if configured. + """ + + self.machine.events.post('ball_save_{}_timer_start'.format(self.name)) + '''event: ball_save_(name)_timer_start + desc: The multiball ball save called (name) has just start its countdown timer. + ''' + + shoot_again_ms = self.config['shoot_again'].evaluate([]) * 1000 + grace_period_ms = self.config['grace_period'].evaluate([]) * 1000 + hurry_up_time_ms = self.config['hurry_up_time'].evaluate([]) * 1000 + if shoot_again_ms > 0: + self.debug_log('Starting ball save timer: %ss', + shoot_again_ms) + # Register stop handler + self.delay.add(name='disable_shoot_again', + ms=(shoot_again_ms + + grace_period_ms), + callback=self.stop) + self.delay.add(name='grace_period', + ms=shoot_again_ms, + callback=self._grace_period) + self.delay.add(name='hurry_up', + ms=(shoot_again_ms - + hurry_up_time_ms), + callback=self._hurry_up) + + def _hurry_up(self) -> None: + self.debug_log("Starting Hurry Up") + + self.machine.events.post('ball_save_{}_hurry_up'.format(self.name)) + '''event: ball_save_(name)_hurry_up + desc: The ball save called (name) has just entered its hurry up mode. + ''' + + def _grace_period(self) -> None: + self.debug_log("Starting Grace Period") + + self.machine.events.post('ball_save_{}_grace_period'.format(self.name)) + '''event: ball_save_(name)_grace_period + desc: The ball save called (name) has just entered its grace period + time. + ''' + def _ball_drain_shoot_again(self, balls, **kwargs): del kwargs @@ -158,8 +201,8 @@ def _ball_drain_shoot_again(self, balls, **kwargs): if balls_to_safe > balls: balls_to_safe = balls - self.machine.events.post("multiball_" + self.name + "_shoot_again", balls=balls_to_safe) - '''event: multiball_(name)_shoot_again + self.machine.events.post("multiball_" + self.name + "_saving_ball", balls=balls_to_safe) + '''event: multiball_(name)_saving_ball desc: A ball has drained during the multiball called (name) while the ball save timer for that multiball was running, so a ball (or balls) will be saved and re-added into play. diff --git a/mpf/tests/machine_files/multiball/config/config.yaml b/mpf/tests/machine_files/multiball/config/config.yaml index 887d9f178..5ca79bddf 100644 --- a/mpf/tests/machine_files/multiball/config/config.yaml +++ b/mpf/tests/machine_files/multiball/config/config.yaml @@ -106,6 +106,13 @@ multiballs: add_a_ball_events: add_ball mb_placeholder: ball_count: 2 - shoot_again: machine.shoot_again_sec * 1000 + shoot_again: machine.shoot_again_sec start_events: mb_placeholder_start stop_events: mb_placeholder_stop + mb_alltimers: + ball_count: 2 + shoot_again: 30s + hurry_up_time: 10s + grace_period: 5s + start_events: mb_alltimers_start + stop_events: mb_alltimers_stop diff --git a/mpf/tests/test_MultiBall.py b/mpf/tests/test_MultiBall.py index d93728314..6c8c318db 100644 --- a/mpf/tests/test_MultiBall.py +++ b/mpf/tests/test_MultiBall.py @@ -1032,3 +1032,55 @@ def testShootAgainPlaceholder(self): self.assertAvailableBallsOnPlayfield(1) # mb should end self.assertEventCalled("multiball_mb_placeholder_ended") + + def testShootAgainHurryUpAndGracePeriod(self): + self.fill_troughs() + self.start_game() + self.assertAvailableBallsOnPlayfield(1) + self.mock_event("multiball_mb_alltimers_ended") + self.mock_event("multiball_mb_alltimers_shoot_again_ended") + self.mock_event("ball_save_mb_alltimers_grace_period") + self.mock_event("ball_save_mb_alltimers_hurry_up") + + # start mb 30s shoot again, 10s hurry up, 5s grace + self.post_event("mb_alltimers_start") + self.advance_time_and_run(5) + self.assertAvailableBallsOnPlayfield(2) + + # drain one ball + self.drain_one_ball() + self.advance_time_and_run(5) + # shoot again should bring it back + self.assertAvailableBallsOnPlayfield(2) + self.assertEventNotCalled("multiball_mb_alltimers_ended") + self.assertEventNotCalled("multiball_mb_alltimers_shoot_again_ended") + self.assertEventNotCalled("ball_save_mb_alltimers_grace_period") + self.assertEventNotCalled("ball_save_mb_alltimers_hurry_up") + + #advance time to hurry up + self.advance_time_and_run(10) + self.assertEventCalled("ball_save_mb_alltimers_hurry_up") + self.assertAvailableBallsOnPlayfield(2) + self.assertEventNotCalled("multiball_mb_alltimers_ended") + self.assertEventNotCalled("multiball_mb_alltimers_shoot_again_ended") + self.assertEventNotCalled("ball_save_mb_alltimers_grace_period") + + # drain one ball + self.drain_one_ball() + self.advance_time_and_run(5) + # shoot again should bring it back + self.assertAvailableBallsOnPlayfield(2) + + # wait 7s for shoot again to end, but within grace period + self.advance_time_and_run(7) + self.assertEventCalled("ball_save_mb_alltimers_grace_period") + self.assertEventNotCalled("multiball_mb_alltimers_ended") + self.assertEventNotCalled("multiball_mb_alltimers_shoot_again_ended") + + # drain one ball after grace period has ended + self.advance_time_and_run(5) + self.drain_one_ball() + self.advance_time_and_run(5) + self.assertAvailableBallsOnPlayfield(1) + # mb should end + self.assertEventCalled("multiball_mb_alltimers_ended") From c5a6ec5013246509574b0471beef30b926db00cd Mon Sep 17 00:00:00 2001 From: Avery Tummons Date: Sun, 1 Aug 2021 20:29:48 -0500 Subject: [PATCH 2/9] Adds additional ball save features to multiballs Adds hurry up and grace period --- mpf/config_spec.yaml | 9 +++------ mpf/devices/multiball.py | 8 ++++---- mpf/tests/machine_files/multiball/config/config.yaml | 2 +- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/mpf/config_spec.yaml b/mpf/config_spec.yaml index eba776b95..2758be7cb 100644 --- a/mpf/config_spec.yaml +++ b/mpf/config_spec.yaml @@ -971,9 +971,9 @@ multiballs: ball_count_type: single|enum(add,total)|total replace_balls_in_play: single|bool|false source_playfield: single|machine(ball_devices)|playfield - shoot_again: single|template_secs|10s - hurry_up_time: single|template_secs|0 - grace_period: single|template_secs|0 + shoot_again: single|template_ms|10s + hurry_up_time: single|template_ms|0 + grace_period: single|template_ms|0 ball_locks: list|machine(ball_devices)|None enable_events: event_handler|event_handler:ms|None disable_events: event_handler|event_handler:ms|None @@ -981,9 +981,6 @@ multiballs: start_events: event_handler|event_handler:ms|None stop_events: event_handler|event_handler:ms|None add_a_ball_events: event_handler|event_handler:ms|None - add_a_ball_shoot_again: single|template_secs|3s - add_a_ball_hurry_up_time: single|ms|0 - add_a_ball_grace_period: single|ms|0 start_or_add_a_ball_events: event_handler|event_handler:ms|None multiball_locks: __valid_in__: mode diff --git a/mpf/devices/multiball.py b/mpf/devices/multiball.py index 75c7abb06..d2f4cb1c2 100644 --- a/mpf/devices/multiball.py +++ b/mpf/devices/multiball.py @@ -124,7 +124,7 @@ def start(self): if self.balls_added_live - balls_added > 0: self.source_playfield.add_ball(balls=self.balls_added_live - balls_added) - shoot_again_ms = self.config['shoot_again'].evaluate([]) * 1000 + shoot_again_ms = self.config['shoot_again'].evaluate([]) if not shoot_again_ms: # No shoot again. Just stop multiball right away self.stop() @@ -154,9 +154,9 @@ def timer_start(self) -> None: desc: The multiball ball save called (name) has just start its countdown timer. ''' - shoot_again_ms = self.config['shoot_again'].evaluate([]) * 1000 - grace_period_ms = self.config['grace_period'].evaluate([]) * 1000 - hurry_up_time_ms = self.config['hurry_up_time'].evaluate([]) * 1000 + shoot_again_ms = self.config['shoot_again'].evaluate([]) + grace_period_ms = self.config['grace_period'].evaluate([]) + hurry_up_time_ms = self.config['hurry_up_time'].evaluate([]) if shoot_again_ms > 0: self.debug_log('Starting ball save timer: %ss', shoot_again_ms) diff --git a/mpf/tests/machine_files/multiball/config/config.yaml b/mpf/tests/machine_files/multiball/config/config.yaml index 5ca79bddf..7953f4973 100644 --- a/mpf/tests/machine_files/multiball/config/config.yaml +++ b/mpf/tests/machine_files/multiball/config/config.yaml @@ -106,7 +106,7 @@ multiballs: add_a_ball_events: add_ball mb_placeholder: ball_count: 2 - shoot_again: machine.shoot_again_sec + shoot_again: machine.shoot_again_sec * 1000 start_events: mb_placeholder_start stop_events: mb_placeholder_stop mb_alltimers: From affcad2fa01fcb011af84de3a99b05779b19fd83 Mon Sep 17 00:00:00 2001 From: Avery Tummons Date: Sun, 1 Aug 2021 20:32:45 -0500 Subject: [PATCH 3/9] Added hurry up and grace period features to the multiball ball save. This allows the user to run shows off the hurry up, as well as provide a grace period for saves. The tests for test_Modes are failing when I run bulk, but run fine when I run just them. So not sure what is going on there. If you also see this issue, please let me know what I changed or need to do to fix that issue. If this is approved and merged, I would also like to go add similar features for add_a_ball to provide a different and shorter ball save feature. --- mpf/devices/multiball.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mpf/devices/multiball.py b/mpf/devices/multiball.py index d2f4cb1c2..197e6bf65 100644 --- a/mpf/devices/multiball.py +++ b/mpf/devices/multiball.py @@ -201,8 +201,8 @@ def _ball_drain_shoot_again(self, balls, **kwargs): if balls_to_safe > balls: balls_to_safe = balls - self.machine.events.post("multiball_" + self.name + "_saving_ball", balls=balls_to_safe) - '''event: multiball_(name)_saving_ball + self.machine.events.post("multiball_" + self.name + "_shoot_again", balls=balls_to_safe) + '''event: multiball_(name)_shoot_again desc: A ball has drained during the multiball called (name) while the ball save timer for that multiball was running, so a ball (or balls) will be saved and re-added into play. From b242a181876fc9f1ea8c90c78f32420ed7a8d8a6 Mon Sep 17 00:00:00 2001 From: Avery Tummons Date: Sun, 1 Aug 2021 20:51:23 -0500 Subject: [PATCH 4/9] Pleas enter the commit message for your changes. Lines starting --- mpf/devices/multiball.py | 12 ++++++------ mpf/tests/test_MultiBall.py | 14 +++++++------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/mpf/devices/multiball.py b/mpf/devices/multiball.py index 197e6bf65..d8f1c41b4 100644 --- a/mpf/devices/multiball.py +++ b/mpf/devices/multiball.py @@ -176,17 +176,17 @@ def timer_start(self) -> None: def _hurry_up(self) -> None: self.debug_log("Starting Hurry Up") - self.machine.events.post('ball_save_{}_hurry_up'.format(self.name)) - '''event: ball_save_(name)_hurry_up - desc: The ball save called (name) has just entered its hurry up mode. + self.machine.events.post('multiball_{}_hurry_up'.format(self.name)) + '''event: multiball_(name)_hurry_up + desc: The multiball ball save called (name) has just entered its hurry up mode. ''' def _grace_period(self) -> None: self.debug_log("Starting Grace Period") - self.machine.events.post('ball_save_{}_grace_period'.format(self.name)) - '''event: ball_save_(name)_grace_period - desc: The ball save called (name) has just entered its grace period + self.machine.events.post('multiball_{}_grace_period'.format(self.name)) + '''event: multiball_(name)_grace_period + desc: The multiball ball save called (name) has just entered its grace period time. ''' diff --git a/mpf/tests/test_MultiBall.py b/mpf/tests/test_MultiBall.py index 6c8c318db..f8e034f0b 100644 --- a/mpf/tests/test_MultiBall.py +++ b/mpf/tests/test_MultiBall.py @@ -1039,8 +1039,8 @@ def testShootAgainHurryUpAndGracePeriod(self): self.assertAvailableBallsOnPlayfield(1) self.mock_event("multiball_mb_alltimers_ended") self.mock_event("multiball_mb_alltimers_shoot_again_ended") - self.mock_event("ball_save_mb_alltimers_grace_period") - self.mock_event("ball_save_mb_alltimers_hurry_up") + self.mock_event("multiball_mb_alltimers_grace_period") + self.mock_event("multiball_mb_alltimers_hurry_up") # start mb 30s shoot again, 10s hurry up, 5s grace self.post_event("mb_alltimers_start") @@ -1054,16 +1054,16 @@ def testShootAgainHurryUpAndGracePeriod(self): self.assertAvailableBallsOnPlayfield(2) self.assertEventNotCalled("multiball_mb_alltimers_ended") self.assertEventNotCalled("multiball_mb_alltimers_shoot_again_ended") - self.assertEventNotCalled("ball_save_mb_alltimers_grace_period") - self.assertEventNotCalled("ball_save_mb_alltimers_hurry_up") + self.assertEventNotCalled("multiball_mb_alltimers_grace_period") + self.assertEventNotCalled("multiball_mb_alltimers_hurry_up") #advance time to hurry up self.advance_time_and_run(10) - self.assertEventCalled("ball_save_mb_alltimers_hurry_up") + self.assertEventCalled("multiball_mb_alltimers_hurry_up") self.assertAvailableBallsOnPlayfield(2) self.assertEventNotCalled("multiball_mb_alltimers_ended") self.assertEventNotCalled("multiball_mb_alltimers_shoot_again_ended") - self.assertEventNotCalled("ball_save_mb_alltimers_grace_period") + self.assertEventNotCalled("multiball_mb_alltimers_grace_period") # drain one ball self.drain_one_ball() @@ -1073,7 +1073,7 @@ def testShootAgainHurryUpAndGracePeriod(self): # wait 7s for shoot again to end, but within grace period self.advance_time_and_run(7) - self.assertEventCalled("ball_save_mb_alltimers_grace_period") + self.assertEventCalled("multiball_mb_alltimers_grace_period") self.assertEventNotCalled("multiball_mb_alltimers_ended") self.assertEventNotCalled("multiball_mb_alltimers_shoot_again_ended") From 41f5b43e5b0f69a014a7b478fe49ed72ca6ed795 Mon Sep 17 00:00:00 2001 From: Avery Tummons Date: Mon, 2 Aug 2021 08:59:34 -0500 Subject: [PATCH 5/9] Test of fixing errors --- mpf/devices/multiball.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mpf/devices/multiball.py b/mpf/devices/multiball.py index d8f1c41b4..90f53af14 100644 --- a/mpf/devices/multiball.py +++ b/mpf/devices/multiball.py @@ -148,7 +148,6 @@ def timer_start(self) -> None: This is started when multiball starts if configured. """ - self.machine.events.post('ball_save_{}_timer_start'.format(self.name)) '''event: ball_save_(name)_timer_start desc: The multiball ball save called (name) has just start its countdown timer. @@ -163,7 +162,7 @@ def timer_start(self) -> None: # Register stop handler self.delay.add(name='disable_shoot_again', ms=(shoot_again_ms + - grace_period_ms), + grace_period_ms), callback=self.stop) self.delay.add(name='grace_period', ms=shoot_again_ms, From 6d0cab4d172e5129f6e18e7f6761d06a4b4c5d27 Mon Sep 17 00:00:00 2001 From: Avery Tummons Date: Mon, 9 Aug 2021 09:34:26 -0500 Subject: [PATCH 6/9] Adds mode stop handling for ball save features --- mpf/devices/multiball.py | 12 ++++++- .../multiball/config/config.yaml | 1 + .../multiball/modes/mode5/config/mode5.yaml | 13 +++++++ mpf/tests/test_MultiBall.py | 36 +++++++++++++++++++ 4 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 mpf/tests/machine_files/multiball/modes/mode5/config/mode5.yaml diff --git a/mpf/devices/multiball.py b/mpf/devices/multiball.py index 90f53af14..ace6bc359 100644 --- a/mpf/devices/multiball.py +++ b/mpf/devices/multiball.py @@ -242,9 +242,19 @@ def stop(self): self.debug_log("Stopping shoot again of multiball") self.shoot_again = False - # disable shoot again + # disable shoot again, grace period, and hurry up + self.machine.events.remove_handler(self._grace_period) + self.machine.events.remove_handler(self._hurry_up) self.machine.events.remove_handler(self._ball_drain_shoot_again) + self.machine.events.post("multiball_" + self.name + "_grace_period") + '''event: multiball_(name)_grace_period + desc: Grace period for multiball (name) has occurred due to mode stop. + ''' + self.machine.events.post("multiball_" + self.name + "_hurry_up") + '''event: multiball_(name)_hurry_up + desc: Hurry Up for multiball (name) has occurred due to mode stop. + ''' self.machine.events.post("multiball_" + self.name + "_shoot_again_ended") '''event: multiball_(name)_shoot_again_ended desc: Shoot again for multiball (name) has ended. diff --git a/mpf/tests/machine_files/multiball/config/config.yaml b/mpf/tests/machine_files/multiball/config/config.yaml index 7953f4973..ea3d0d0f0 100644 --- a/mpf/tests/machine_files/multiball/config/config.yaml +++ b/mpf/tests/machine_files/multiball/config/config.yaml @@ -69,6 +69,7 @@ modes: - mode2 - mode3 - mode4 + - mode5 multiballs: mb1: diff --git a/mpf/tests/machine_files/multiball/modes/mode5/config/mode5.yaml b/mpf/tests/machine_files/multiball/modes/mode5/config/mode5.yaml new file mode 100644 index 000000000..7acdc85d8 --- /dev/null +++ b/mpf/tests/machine_files/multiball/modes/mode5/config/mode5.yaml @@ -0,0 +1,13 @@ +#config_version=5 +mode: + start_events: start_mode5 + stop_events: stop_mode5 + +multiballs: + mb_mode5: + ball_count: 2 + shoot_again: 30s + hurry_up_time: 10s + grace_period: 5s + start_events: mb_mode5_start + stop_events: mb_mode5_stop \ No newline at end of file diff --git a/mpf/tests/test_MultiBall.py b/mpf/tests/test_MultiBall.py index f8e034f0b..0809c69d0 100644 --- a/mpf/tests/test_MultiBall.py +++ b/mpf/tests/test_MultiBall.py @@ -1084,3 +1084,39 @@ def testShootAgainHurryUpAndGracePeriod(self): self.assertAvailableBallsOnPlayfield(1) # mb should end self.assertEventCalled("multiball_mb_alltimers_ended") + + def testShootAgainModeEnd(self): + self.fill_troughs() + self.start_game() + self.assertAvailableBallsOnPlayfield(1) + self.mock_event("multiball_mb_mode5_ended") + self.mock_event("multiball_mb_mode5_shoot_again_ended") + self.mock_event("multiball_mb_mode5_grace_period") + self.mock_event("multiball_mb_mode5_hurry_up") + + #start Mode5 + self.post_event("start_mode5") + + # start mb 30s shoot again, 10s hurry up, 5s grace + self.post_event("mb_mode5_start") + self.advance_time_and_run(5) + self.assertAvailableBallsOnPlayfield(2) + self.assertEventNotCalled("multiball_mb_mode5_ended") + self.assertEventNotCalled("multiball_mb_mode5_shoot_again_ended") + self.assertEventNotCalled("multiball_mb_mode5_grace_period") + self.assertEventNotCalled("multiball_mb_mode5_hurry_up") + + #stop Mode5 + self.post_event("stop_mode5") + self.advance_time_and_run(5) + self.assertEventNotCalled("multiball_mb_mode5_ended") + self.assertEventCalled("multiball_mb_mode5_shoot_again_ended") + self.assertEventCalled("multiball_mb_mode5_grace_period") + self.assertEventCalled("multiball_mb_mode5_hurry_up") + + # drain one ball + self.drain_one_ball() + self.advance_time_and_run(5) + # shoot again should not bring it back + self.assertAvailableBallsOnPlayfield(1) + self.assertEventCalled("multiball_mb_mode5_ended") \ No newline at end of file From 27613c696ef1433066e3946245f48fc8f5f4c99b Mon Sep 17 00:00:00 2001 From: Avery Tummons Date: Mon, 9 Aug 2021 09:37:56 -0500 Subject: [PATCH 7/9] Adds blank line to end of file --- mpf/tests/test_MultiBall.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mpf/tests/test_MultiBall.py b/mpf/tests/test_MultiBall.py index 0809c69d0..13f9ed543 100644 --- a/mpf/tests/test_MultiBall.py +++ b/mpf/tests/test_MultiBall.py @@ -1119,4 +1119,5 @@ def testShootAgainModeEnd(self): self.advance_time_and_run(5) # shoot again should not bring it back self.assertAvailableBallsOnPlayfield(1) - self.assertEventCalled("multiball_mb_mode5_ended") \ No newline at end of file + self.assertEventCalled("multiball_mb_mode5_ended") + \ No newline at end of file From d764312b396d16dda0344f31613c44f103ec2610 Mon Sep 17 00:00:00 2001 From: Avery Tummons Date: Mon, 9 Aug 2021 10:21:03 -0500 Subject: [PATCH 8/9] Adds additional handling for mode end conditions --- mpf/devices/multiball.py | 39 ++++++++++++------- .../multiball/modes/mode5/config/mode5.yaml | 2 +- mpf/tests/test_MultiBall.py | 1 - 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/mpf/devices/multiball.py b/mpf/devices/multiball.py index ace6bc359..94234855f 100644 --- a/mpf/devices/multiball.py +++ b/mpf/devices/multiball.py @@ -9,7 +9,7 @@ from mpf.core.system_wide_device import SystemWideDevice -@DeviceMonitor("shoot_again", "balls_added_live", "balls_live_target") +@DeviceMonitor("shoot_again", "grace_period", "hurry_up", "balls_added_live", "balls_live_target") class Multiball(EnableDisableMixin, SystemWideDevice, ModeDevice): """Multiball device for MPF.""" @@ -18,7 +18,8 @@ class Multiball(EnableDisableMixin, SystemWideDevice, ModeDevice): collection = 'multiballs' class_label = 'multiball' - __slots__ = ["ball_locks", "source_playfield", "delay", "balls_added_live", "balls_live_target", "shoot_again"] + __slots__ = ["ball_locks", "source_playfield", "delay", "balls_added_live", "balls_live_target", "shoot_again", + "grace_period", "hurry_up"] def __init__(self, machine, name): """Initialise multiball.""" @@ -30,6 +31,8 @@ def __init__(self, machine, name): self.balls_added_live = 0 self.balls_live_target = 0 self.shoot_again = False + self.grace_period = False + self.hurry_up = False @property def can_exist_outside_of_game(self): @@ -164,9 +167,13 @@ def timer_start(self) -> None: ms=(shoot_again_ms + grace_period_ms), callback=self.stop) + if grace_period_ms > 0: + self.grace_period = True self.delay.add(name='grace_period', ms=shoot_again_ms, callback=self._grace_period) + if hurry_up_time_ms > 0: + self.hurry_up = True self.delay.add(name='hurry_up', ms=(shoot_again_ms - hurry_up_time_ms), @@ -175,6 +182,7 @@ def timer_start(self) -> None: def _hurry_up(self) -> None: self.debug_log("Starting Hurry Up") + self.hurry_up = False self.machine.events.post('multiball_{}_hurry_up'.format(self.name)) '''event: multiball_(name)_hurry_up desc: The multiball ball save called (name) has just entered its hurry up mode. @@ -183,6 +191,7 @@ def _hurry_up(self) -> None: def _grace_period(self) -> None: self.debug_log("Starting Grace Period") + self.grace_period = False self.machine.events.post('multiball_{}_grace_period'.format(self.name)) '''event: multiball_(name)_grace_period desc: The multiball ball save called (name) has just entered its grace period @@ -242,19 +251,23 @@ def stop(self): self.debug_log("Stopping shoot again of multiball") self.shoot_again = False - # disable shoot again, grace period, and hurry up - self.machine.events.remove_handler(self._grace_period) - self.machine.events.remove_handler(self._hurry_up) + # disable shoot again self.machine.events.remove_handler(self._ball_drain_shoot_again) - self.machine.events.post("multiball_" + self.name + "_grace_period") - '''event: multiball_(name)_grace_period - desc: Grace period for multiball (name) has occurred due to mode stop. - ''' - self.machine.events.post("multiball_" + self.name + "_hurry_up") - '''event: multiball_(name)_hurry_up - desc: Hurry Up for multiball (name) has occurred due to mode stop. - ''' + if self.grace_period: + self.machine.events.remove_handler(self._grace_period) + self.grace_period = False + self.machine.events.post("multiball_" + self.name + "_grace_period") + '''event: multiball_(name)_grace_period + desc: Grace period for multiball (name) has occurred due to mode stop. + ''' + if self.hurry_up: + self.machine.events.remove_handler(self._hurry_up) + self.hurry_up = False + self.machine.events.post("multiball_" + self.name + "_hurry_up") + '''event: multiball_(name)_hurry_up + desc: Hurry Up for multiball (name) has occurred due to mode stop. + ''' self.machine.events.post("multiball_" + self.name + "_shoot_again_ended") '''event: multiball_(name)_shoot_again_ended desc: Shoot again for multiball (name) has ended. diff --git a/mpf/tests/machine_files/multiball/modes/mode5/config/mode5.yaml b/mpf/tests/machine_files/multiball/modes/mode5/config/mode5.yaml index 7acdc85d8..7a957200e 100644 --- a/mpf/tests/machine_files/multiball/modes/mode5/config/mode5.yaml +++ b/mpf/tests/machine_files/multiball/modes/mode5/config/mode5.yaml @@ -10,4 +10,4 @@ multiballs: hurry_up_time: 10s grace_period: 5s start_events: mb_mode5_start - stop_events: mb_mode5_stop \ No newline at end of file + stop_events: mb_mode5_stop diff --git a/mpf/tests/test_MultiBall.py b/mpf/tests/test_MultiBall.py index 13f9ed543..7d6e8fa30 100644 --- a/mpf/tests/test_MultiBall.py +++ b/mpf/tests/test_MultiBall.py @@ -1120,4 +1120,3 @@ def testShootAgainModeEnd(self): # shoot again should not bring it back self.assertAvailableBallsOnPlayfield(1) self.assertEventCalled("multiball_mb_mode5_ended") - \ No newline at end of file From b532e4e8c7cdbdaa3309da4ed66ecbd1fbc1aea6 Mon Sep 17 00:00:00 2001 From: Avery Tummons Date: Mon, 9 Aug 2021 15:08:38 -0500 Subject: [PATCH 9/9] Adds additional test case Adds another test case to ensure that when grace period and hurry up are not set, that they are never called in an event. --- .../multiball/modes/mode5/config/mode5.yaml | 6 +++ mpf/tests/test_MultiBall.py | 38 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/mpf/tests/machine_files/multiball/modes/mode5/config/mode5.yaml b/mpf/tests/machine_files/multiball/modes/mode5/config/mode5.yaml index 7a957200e..42c9ba096 100644 --- a/mpf/tests/machine_files/multiball/modes/mode5/config/mode5.yaml +++ b/mpf/tests/machine_files/multiball/modes/mode5/config/mode5.yaml @@ -11,3 +11,9 @@ multiballs: grace_period: 5s start_events: mb_mode5_start stop_events: mb_mode5_stop + + mb_mode5_lean: + ball_count: 2 + shoot_again: 30s + start_events: mb_mode5_lean_start + stop_events: mb_mode5_lean_stop diff --git a/mpf/tests/test_MultiBall.py b/mpf/tests/test_MultiBall.py index 7d6e8fa30..555f8ed8a 100644 --- a/mpf/tests/test_MultiBall.py +++ b/mpf/tests/test_MultiBall.py @@ -1120,3 +1120,41 @@ def testShootAgainModeEnd(self): # shoot again should not bring it back self.assertAvailableBallsOnPlayfield(1) self.assertEventCalled("multiball_mb_mode5_ended") + + def testShootAgainModeEndNoGracePeriodOrHurryUp(self): + self.fill_troughs() + self.start_game() + self.assertAvailableBallsOnPlayfield(1) + self.mock_event("multiball_mb_mode5_lean_ended") + self.mock_event("multiball_mb_mode5_lean_shoot_again_ended") + self.mock_event("multiball_mb_mode5_lean_grace_period") + self.mock_event("multiball_mb_mode5_lean_hurry_up") + + #start Mode5 + self.post_event("start_mode5") + + # start mb 30s shoot again + self.post_event("mb_mode5_lean_start") + self.advance_time_and_run(5) + self.assertAvailableBallsOnPlayfield(2) + self.assertEventNotCalled("multiball_mb_mode5_lean_ended") + self.assertEventNotCalled("multiball_mb_mode5_lean_shoot_again_ended") + self.assertEventNotCalled("multiball_mb_mode5_lean_grace_period") + self.assertEventNotCalled("multiball_mb_mode5_lean_hurry_up") + + #stop Mode5 + self.post_event("stop_mode5") + self.advance_time_and_run(5) + self.assertEventNotCalled("multiball_mb_mode5_lean_ended") + self.assertEventCalled("multiball_mb_mode5_lean_shoot_again_ended") + self.assertEventNotCalled("multiball_mb_mode5_lean_grace_period") + self.assertEventNotCalled("multiball_mb_mode5_lean_hurry_up") + + # drain one ball + self.drain_one_ball() + self.advance_time_and_run(5) + # shoot again should not bring it back + self.assertAvailableBallsOnPlayfield(1) + self.assertEventCalled("multiball_mb_mode5_lean_ended") + self.assertEventNotCalled("multiball_mb_mode5_lean_grace_period") + self.assertEventNotCalled("multiball_mb_mode5_lean_hurry_up")