From fa6caffd40acbdb8db73771656c1c2bd942f7602 Mon Sep 17 00:00:00 2001 From: Jan Kantert Date: Sat, 8 Apr 2017 14:05:54 +0200 Subject: [PATCH 1/5] pass event kwargs to scoring placeholders --- mpf/config_players/score_player.py | 12 ++++++------ .../scoring/modes/mode1/config/mode1.yaml | 6 +++++- mpf/tests/test_Scoring.py | 2 ++ 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/mpf/config_players/score_player.py b/mpf/config_players/score_player.py index 2f8c73441..2db84083f 100644 --- a/mpf/config_players/score_player.py +++ b/mpf/config_players/score_player.py @@ -26,7 +26,7 @@ def play(self, settings, context, calling_context, priority=0, **kwargs): if (priority, context, calling_context) not in self.blocks[var]: self.blocks[var].append((priority, context, calling_context)) - self._score(var, s) + self._score(var, s, kwargs) def _is_blocked(self, var, context, calling_context): if var not in self.blocks or not self.blocks[var]: @@ -34,20 +34,20 @@ def _is_blocked(self, var, context, calling_context): priority_sorted = sorted(self.blocks[var], reverse=True) return priority_sorted[0][1] != context + "_" + calling_context - def _score(self, var, entry): + def _score(self, var: str, entry: dict, placeholder_parameters: dict) -> None: if entry['string']: self.machine.game.player[var] = entry['string'] elif entry['action'] == "add": - self.machine.game.player[var] += entry['score'].evaluate([]) + self.machine.game.player[var] += entry['score'].evaluate(placeholder_parameters) elif entry['action'] == "set": - self.machine.game.player[var] = entry['score'].evaluate([]) + self.machine.game.player[var] = entry['score'].evaluate(placeholder_parameters) elif entry['action'] == "add_machine": value = self.machine.get_machine_var(var) if value is None: value = 0 - self.machine.create_machine_var(var, value + entry['score'].evaluate([])) + self.machine.create_machine_var(var, value + entry['score'].evaluate(placeholder_parameters)) elif entry['action'] == "set_machine": - self.machine.create_machine_var(var, entry['score'].evaluate([])) + self.machine.create_machine_var(var, entry['score'].evaluate(placeholder_parameters)) else: raise AssertionError("Invalid value: {}".format(entry)) diff --git a/mpf/tests/machine_files/scoring/modes/mode1/config/mode1.yaml b/mpf/tests/machine_files/scoring/modes/mode1/config/mode1.yaml index 42232727a..812596f8e 100644 --- a/mpf/tests/machine_files/scoring/modes/mode1/config/mode1.yaml +++ b/mpf/tests/machine_files/scoring/modes/mode1/config/mode1.yaml @@ -27,4 +27,8 @@ scoring: test_add_machine_var: my_var: score: 23 - action: add_machine \ No newline at end of file + action: add_machine + player_score: + my_var2: + score: change + action: add_machine diff --git a/mpf/tests/test_Scoring.py b/mpf/tests/test_Scoring.py index 74c5db276..b503b404a 100644 --- a/mpf/tests/test_Scoring.py +++ b/mpf/tests/test_Scoring.py @@ -57,11 +57,13 @@ def test_scoring(self): self.assertEqual(1, self.machine.game.player.vars['var_a']) self.assertEqual(0, self.machine.game.player.var_c) self.machine.game.player.ramps = 3 + self.assertMachineVarEqual(100, "my_var2") self.post_event("test_event1") self.assertEqual(200, self.machine.game.player.score) self.assertEqual(2, self.machine.game.player.vars['var_a']) self.assertEqual(3, self.machine.game.player.var_c) + self.assertMachineVarEqual(200, "my_var2") self.post_event("test_set_100") self.assertEqual(100, self.machine.game.player.test1) From d5cfd6c5234f10e0ce556f740c14feaf4528bff8 Mon Sep 17 00:00:00 2001 From: Jan Kantert Date: Sat, 8 Apr 2017 14:45:27 +0200 Subject: [PATCH 2/5] fix priority bug and allow scoring for other players --- mpf/config_players/score_player.py | 37 +++++++++++++------ mpf/core/config_spec.py | 1 + .../machine_files/scoring/config/config.yaml | 3 +- .../scoring/modes/mode3/config/mode3.yaml | 20 ++++++++++ mpf/tests/test_Scoring.py | 17 +++++++++ 5 files changed, 66 insertions(+), 12 deletions(-) create mode 100644 mpf/tests/machine_files/scoring/modes/mode3/config/mode3.yaml diff --git a/mpf/config_players/score_player.py b/mpf/config_players/score_player.py index 2db84083f..f9a39c78c 100644 --- a/mpf/config_players/score_player.py +++ b/mpf/config_players/score_player.py @@ -18,7 +18,7 @@ def __init__(self, machine): def play(self, settings, context, calling_context, priority=0, **kwargs): """Score variable.""" for var, s in settings.items(): - if self._is_blocked(var, context, calling_context): + if self._is_blocked(var, context, calling_context, priority): continue if s['block']: if var not in self.blocks: @@ -28,26 +28,41 @@ def play(self, settings, context, calling_context, priority=0, **kwargs): self._score(var, s, kwargs) - def _is_blocked(self, var, context, calling_context): + def _is_blocked(self, var, context, calling_context, priority): if var not in self.blocks or not self.blocks[var]: return False priority_sorted = sorted(self.blocks[var], reverse=True) - return priority_sorted[0][1] != context + "_" + calling_context + return priority_sorted[0][0] > priority and priority_sorted[0][1] != context + "_" + calling_context def _score(self, var: str, entry: dict, placeholder_parameters: dict) -> None: if entry['string']: self.machine.game.player[var] = entry['string'] - elif entry['action'] == "add": - self.machine.game.player[var] += entry['score'].evaluate(placeholder_parameters) + return + + # evaluate placeholder + value = entry['score'].evaluate(placeholder_parameters) + + if entry['action'] == "add": + if entry['player']: + # specific player + self.machine.game.player_list[entry['player'] - 1][var] += value + else: + # default to current player + self.machine.game.player[var] += value elif entry['action'] == "set": - self.machine.game.player[var] = entry['score'].evaluate(placeholder_parameters) + if entry['player']: + # specific player + self.machine.game.player_list[entry['player'] - 1][var] = value + else: + # default to current player + self.machine.game.player[var] = value elif entry['action'] == "add_machine": - value = self.machine.get_machine_var(var) - if value is None: - value = 0 - self.machine.create_machine_var(var, value + entry['score'].evaluate(placeholder_parameters)) + old_value = self.machine.get_machine_var(var) + if old_value is None: + old_value = 0 + self.machine.create_machine_var(var, old_value + value) elif entry['action'] == "set_machine": - self.machine.create_machine_var(var, entry['score'].evaluate(placeholder_parameters)) + self.machine.create_machine_var(var, value) else: raise AssertionError("Invalid value: {}".format(entry)) diff --git a/mpf/core/config_spec.py b/mpf/core/config_spec.py index 1690cb3af..e2ac0709e 100644 --- a/mpf/core/config_spec.py +++ b/mpf/core/config_spec.py @@ -841,6 +841,7 @@ score: single|template_int|0 block: single|bool|False action: single|enum(add,set,add_machine,set_machine)|add + player: single|int|None string: single|str|None scriptlets: __valid_in__: machine # todo add to validator diff --git a/mpf/tests/machine_files/scoring/config/config.yaml b/mpf/tests/machine_files/scoring/config/config.yaml index 05a48b606..fd6b46bf3 100644 --- a/mpf/tests/machine_files/scoring/config/config.yaml +++ b/mpf/tests/machine_files/scoring/config/config.yaml @@ -25,4 +25,5 @@ ball_devices: modes: - mode1 - - mode2 \ No newline at end of file + - mode2 + - mode3 \ No newline at end of file diff --git a/mpf/tests/machine_files/scoring/modes/mode3/config/mode3.yaml b/mpf/tests/machine_files/scoring/modes/mode3/config/mode3.yaml new file mode 100644 index 000000000..982dc541e --- /dev/null +++ b/mpf/tests/machine_files/scoring/modes/mode3/config/mode3.yaml @@ -0,0 +1,20 @@ +#config_version=4 +mode: + start_events: start_mode3 + stop_events: stop_mode3 + priority: 400 + +scoring: + score_player1: + score: + score: 42 + player: 1 + score_player2: + score: + score: 23 + player: 2 + reset_player2: + score: + score: 10 + player: 2 + action: set diff --git a/mpf/tests/test_Scoring.py b/mpf/tests/test_Scoring.py index b503b404a..1cf778984 100644 --- a/mpf/tests/test_Scoring.py +++ b/mpf/tests/test_Scoring.py @@ -132,6 +132,23 @@ def test_scoring(self): self.assertEqual(2, self.machine.game.player.vars['var_a']) self.assertEqual(2, self.machine.game.player.vars['var_b']) + self.post_event("start_mode3") + self.advance_time_and_run() + + self.assertPlayerVarEqual(2200, "score") + self.assertEqual(1000, self.machine.game.player_list[1].score) + self.post_event("score_player2") + self.assertPlayerVarEqual(2200, "score") + self.assertEqual(1023, self.machine.game.player_list[1].score) + + self.post_event("score_player1") + self.assertPlayerVarEqual(2242, "score") + self.assertEqual(1023, self.machine.game.player_list[1].score) + + self.post_event("reset_player2") + self.assertPlayerVarEqual(2242, "score") + self.assertEqual(10, self.machine.game.player_list[1].score) + # stop game and mode self.machine.service.start_service() self.advance_time_and_run() From 1fc3752587cbd2f75f80517683b1d38a7d92c971 Mon Sep 17 00:00:00 2001 From: Jan Kantert Date: Sat, 8 Apr 2017 18:03:27 +0200 Subject: [PATCH 3/5] bump version to dev18 --- mpf/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mpf/_version.py b/mpf/_version.py index 293fb14e2..0bfe9f4f3 100644 --- a/mpf/_version.py +++ b/mpf/_version.py @@ -10,7 +10,7 @@ """ -__version__ = '0.33.0-dev.17' +__version__ = '0.33.0-dev.18' __short_version__ = '0.33' __bcp_version__ = '1.1' __config_version__ = '4' From f9b309d59e2079d3bb45ead83dcf7627e10c6096 Mon Sep 17 00:00:00 2001 From: Jan Kantert Date: Mon, 10 Apr 2017 13:31:39 +0200 Subject: [PATCH 4/5] allow unlimited delay in ball_save --- mpf/core/ball_controller.py | 3 +- mpf/core/config_spec.py | 1 + mpf/devices/ball_save.py | 70 +++++++++----- mpf/tests/MpfGameTestCase.py | 5 +- .../ball_save/config/config.yaml | 5 +- mpf/tests/test_BallSave.py | 92 ++++++++++--------- 6 files changed, 105 insertions(+), 71 deletions(-) diff --git a/mpf/core/ball_controller.py b/mpf/core/ball_controller.py index 129fc83fb..0273227d9 100644 --- a/mpf/core/ball_controller.py +++ b/mpf/core/ball_controller.py @@ -97,7 +97,8 @@ def _add_new_balls_to_playfield(self): self.info_log("Found a new ball which was captured from %s. Known balls: %s", capture.name, self.num_balls_known) - self._balance_playfields() + if len(self.machine.playfields) > 1: + self._balance_playfields() def _balance_playfields(self): # find negative counts diff --git a/mpf/core/config_spec.py b/mpf/core/config_spec.py index e2ac0709e..ca74bbc1b 100644 --- a/mpf/core/config_spec.py +++ b/mpf/core/config_spec.py @@ -188,6 +188,7 @@ balls_to_save: single|int|1 enable_events: dict|str:ms|None early_ball_save_events: dict|str:ms|None + delayed_eject_events: dict|str:ms|None disable_events: dict|str:ms|ball_will_end, service_mode_entered timer_start_events: dict|str:ms|None bcp: diff --git a/mpf/devices/ball_save.py b/mpf/devices/ball_save.py index b67dbaf7b..c34bf126c 100644 --- a/mpf/devices/ball_save.py +++ b/mpf/devices/ball_save.py @@ -1,10 +1,17 @@ """Device that implements a ball save.""" +from typing import TYPE_CHECKING, Optional from mpf.core.delays import DelayManager from mpf.core.device_monitor import DeviceMonitor +from mpf.core.events import event_handler +from mpf.core.mode import Mode from mpf.core.mode_device import ModeDevice from mpf.core.system_wide_device import SystemWideDevice +if TYPE_CHECKING: + from mpf.core.machine import MachineController + from mpf.devices.playfield import Playfield + @DeviceMonitor("saves_remaining", "enabled", "timer_started", "state") class BallSave(SystemWideDevice, ModeDevice): @@ -15,10 +22,10 @@ class BallSave(SystemWideDevice, ModeDevice): collection = 'ball_saves' class_label = 'ball_save' - def __init__(self, machine, name): + def __init__(self, machine: "MachineController", name: str) -> None: """Initialise ball save.""" - self.unlimited_saves = None - self.source_playfield = None + self.unlimited_saves = None # type: bool + self.source_playfield = None # type: Playfield super().__init__(machine, name) self.delay = DelayManager(machine.delayRegistry) @@ -27,20 +34,18 @@ def __init__(self, machine, name): self.saves_remaining = 0 self.early_saved = 0 self.state = 'disabled' + self._scheduled_balls = 0 - def _initialize(self): + def _initialize(self) -> None: self.unlimited_saves = self.config['balls_to_save'] == -1 self.source_playfield = self.config['source_playfield'] - # todo change the delays to timers so we can add pause and extension - # events, but that will require moving timers out of mode conde - @property - def can_exist_outside_of_game(self): + def can_exist_outside_of_game(self) -> bool: """Return true if this device can exist outside of a game.""" return True - def validate_and_parse_config(self, config: dict, is_mode_config: bool): + def validate_and_parse_config(self, config: dict, is_mode_config: bool) -> dict: """Make sure timer_start_events are not in enable_events.""" config = super().validate_and_parse_config(config, is_mode_config) @@ -49,9 +54,13 @@ def validate_and_parse_config(self, config: dict, is_mode_config: bool): raise AssertionError("{}: event {} in timer_start_events will not work because it is also in " "enable_events. Omit it!".format(event, str(self))) + if config['delayed_eject_events'] and config['eject_delay']: + raise AssertionError("cannot use delayed_eject_events and eject_delay at the same time.") + return config - def enable(self, **kwargs): + @event_handler(10) + def enable(self, **kwargs) -> None: """Enable ball save.""" del kwargs if self.enabled: @@ -79,7 +88,8 @@ def enable(self, **kwargs): desc: The ball save called (name) has just been enabled. ''' - def disable(self, **kwargs): + @event_handler(1) + def disable(self, **kwargs) -> None: """Disable ball save.""" del kwargs if not self.enabled: @@ -99,7 +109,8 @@ def disable(self, **kwargs): desc: The ball save called (name) has just been disabled. ''' - def timer_start(self, **kwargs): + @event_handler(9) + def timer_start(self, **kwargs) -> None: """Start the timer. This is usually called after the ball was ejected while the ball save may have been enabled earlier. @@ -131,7 +142,7 @@ def timer_start(self, **kwargs): self.config['hurry_up_time']), callback=self._hurry_up) - def _hurry_up(self): + def _hurry_up(self) -> None: self.debug_log("Starting Hurry Up") self.state = 'hurry_up' @@ -141,7 +152,7 @@ def _hurry_up(self): desc: The ball save called (name) has just entered its hurry up mode. ''' - def _grace_period(self): + def _grace_period(self) -> None: self.debug_log("Starting Grace Period") self.state = 'grace_period' @@ -152,7 +163,7 @@ def _grace_period(self): time. ''' - def _get_number_of_balls_to_save(self, available_balls): + def _get_number_of_balls_to_save(self, available_balls: int) -> int: no_balls_in_play = False try: @@ -183,7 +194,7 @@ def _get_number_of_balls_to_save(self, available_balls): return balls_to_save - def _reduce_remaining_saves_and_disable_if_zero(self, balls_to_save): + def _reduce_remaining_saves_and_disable_if_zero(self, balls_to_save: int) -> None: if not self.unlimited_saves: self.saves_remaining -= balls_to_save self.debug_log("Saves remaining: %s", self.saves_remaining) @@ -194,10 +205,10 @@ def _reduce_remaining_saves_and_disable_if_zero(self, balls_to_save): self.debug_log("Disabling since there are no saves remaining") self.disable() - def _ball_drain_while_active(self, balls, **kwargs): + def _ball_drain_while_active(self, balls: int, **kwargs) -> Optional[dict]: del kwargs if balls <= 0: - return + return {} balls_to_save = self._get_number_of_balls_to_save(balls) @@ -220,7 +231,8 @@ def _ball_drain_while_active(self, balls, **kwargs): return {'balls': balls - balls_to_save} - def early_ball_save(self, **kwargs): + @event_handler(8) + def early_ball_save(self, **kwargs) -> None: """Perform early ball save if enabled.""" del kwargs if not self.enabled: @@ -246,7 +258,7 @@ def early_ball_save(self, **kwargs): self._reduce_remaining_saves_and_disable_if_zero(1) - def _early_ball_save_drain_handler(self, balls, **kwargs): + def _early_ball_save_drain_handler(self, balls: int, **kwargs) -> dict: del kwargs if self.early_saved and balls > 0: balls -= 1 @@ -254,19 +266,33 @@ def _early_ball_save_drain_handler(self, balls, **kwargs): self.debug_log("Early saved ball drained.") self.machine.events.remove_handler(self._early_ball_save_drain_handler) return {'balls': balls} + else: + return {} - def _schedule_balls(self, balls_to_save): + def _schedule_balls(self, balls_to_save: int) -> None: if self.config['eject_delay']: + # schedule after delay. to add some drama self.delay.add(self.config['eject_delay'], self._add_balls, balls_to_save=balls_to_save) + elif self.config['delayed_eject_events']: + # unlimited delay. wait for event + self._scheduled_balls += balls_to_save else: + # default: no delay. just eject balls right now self._add_balls(balls_to_save) + @event_handler(4) + def delayed_eject(self, **kwargs): + """Trigger eject of all scheduled balls.""" + del kwargs + self._add_balls(self._scheduled_balls) + self._scheduled_balls = 0 + def _add_balls(self, balls_to_save, **kwargs): del kwargs self.source_playfield.add_ball(balls=balls_to_save, player_controlled=self.config['auto_launch'] ^ 1) - def device_removed_from_mode(self, mode): + def device_removed_from_mode(self, mode: Mode) -> None: """Disable ball save when mode ends.""" del mode self.debug_log("Removing...") diff --git a/mpf/tests/MpfGameTestCase.py b/mpf/tests/MpfGameTestCase.py index 10d44ebde..aa74a19da 100644 --- a/mpf/tests/MpfGameTestCase.py +++ b/mpf/tests/MpfGameTestCase.py @@ -44,6 +44,7 @@ def add_player(self): self.assertEqual(prev_players + 1, self.machine.game.num_players) def assertBallNumber(self, number): + self.assertGameIsRunning() self.assertEqual(number, self.machine.game.player.ball) def assertBallsInPlay(self, balls): @@ -64,7 +65,7 @@ def stop_game(self): self.assertGameIsNotRunning() def assertGameIsRunning(self): - self.assertIsNotNone(self.machine.game) + self.assertIsNotNone(self.machine.game, "Expected a running game but no game is active.") def assertGameIsNotRunning(self): - self.assertIsNone(self.machine.game) + self.assertIsNone(self.machine.game, "Expected game to have ended but game is active.") diff --git a/mpf/tests/machine_files/ball_save/config/config.yaml b/mpf/tests/machine_files/ball_save/config/config.yaml index d5bd4ba76..1b2912eee 100644 --- a/mpf/tests/machine_files/ball_save/config/config.yaml +++ b/mpf/tests/machine_files/ball_save/config/config.yaml @@ -68,4 +68,7 @@ ball_saves: eject_delay: enable_events: enable4 eject_delay: 1s - debug: yes \ No newline at end of file + debug: yes + unlimited_delay: + enable_events: enable5 + delayed_eject_events: eject5 diff --git a/mpf/tests/test_BallSave.py b/mpf/tests/test_BallSave.py index 25398f81e..20fc44f5b 100644 --- a/mpf/tests/test_BallSave.py +++ b/mpf/tests/test_BallSave.py @@ -27,16 +27,13 @@ def test_ball_save_enable_in_mode(self): def test_early_ball_save_once(self): # prepare game - self.machine.switch_controller.process_switch('s_ball_switch1', 1) - self.machine.switch_controller.process_switch('s_ball_switch2', 1) + self.fill_troughs() 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) # start game - self.machine.switch_controller.process_switch('s_start', 1) - self.machine.switch_controller.process_switch('s_start', 0) - self.machine_run() + self.start_game() self.post_event("enable1") # ball save should be enabled now @@ -76,16 +73,13 @@ def test_early_ball_save_once(self): def test_early_ball_save_unlimited(self): # prepare game - self.machine.switch_controller.process_switch('s_ball_switch1', 1) - self.machine.switch_controller.process_switch('s_ball_switch2', 1) + self.fill_troughs() 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) # start game - self.machine.switch_controller.process_switch('s_start', 1) - self.machine.switch_controller.process_switch('s_start', 0) - self.machine_run() + self.start_game() self.post_event("enable2") # ball save should be enabled now @@ -129,8 +123,7 @@ def test_early_ball_save_unlimited(self): def testBallSaveShootAgain(self): # prepare game - self.machine.switch_controller.process_switch('s_ball_switch1', 1) - self.machine.switch_controller.process_switch('s_ball_switch2', 1) + self.fill_troughs() 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) @@ -138,9 +131,7 @@ def testBallSaveShootAgain(self): self.assertFalse(self.machine.ball_saves.default.enabled) # start game - self.machine.switch_controller.process_switch('s_start', 1) - self.machine.switch_controller.process_switch('s_start', 0) - self.machine_run() + self.start_game() self.post_event("enable1") # ball save should be enabled now @@ -191,8 +182,7 @@ def testBallSaveEvents(self): self._grace_period = False # prepare game - self.machine.switch_controller.process_switch('s_ball_switch1', 1) - self.machine.switch_controller.process_switch('s_ball_switch2', 1) + self.fill_troughs() 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) @@ -201,16 +191,14 @@ def testBallSaveEvents(self): self.assertEqual(0, self._events["ball_save_default_timer_start"]) # start game - self.machine.switch_controller.process_switch('s_start', 1) - self.machine.switch_controller.process_switch('s_start', 0) - self.machine_run() + self.start_game() self.post_event("enable1") # ball save should be enabled now self.assertTrue(self.machine.ball_saves.default.enabled) # takes roughly 4s to get ball confirmed - self.advance_time_and_run(4) + self.advance_time_and_run(3) self.assertEqual(1, self._events["ball_save_default_timer_start"]) self.assertNotEqual(None, self.machine.game) @@ -249,8 +237,7 @@ def testBallSaveUnlimited(self): self.mock_event("ball_save_unlimited_timer_start") # prepare game - self.machine.switch_controller.process_switch('s_ball_switch1', 1) - self.machine.switch_controller.process_switch('s_ball_switch2', 1) + self.fill_troughs() 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) @@ -259,9 +246,7 @@ def testBallSaveUnlimited(self): self.assertEqual(0, self._events["ball_save_unlimited_timer_start"]) # start game - self.machine.switch_controller.process_switch('s_start', 1) - self.machine.switch_controller.process_switch('s_start', 0) - self.machine_run() + self.start_game() # takes roughly 4s to get ball confirmed self.advance_time_and_run(4) @@ -325,8 +310,7 @@ def testBallOutsideGame(self): def testBallDoubleDrain(self): # prepare game - self.machine.switch_controller.process_switch('s_ball_switch1', 1) - self.machine.switch_controller.process_switch('s_ball_switch2', 1) + self.fill_troughs() 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) @@ -334,9 +318,7 @@ def testBallDoubleDrain(self): self.assertFalse(self.machine.ball_saves.default.enabled) # start game - self.machine.switch_controller.process_switch('s_start', 1) - self.machine.switch_controller.process_switch('s_start', 0) - self.machine_run() + self.start_game() self.post_event("enable1") self.machine.playfield.add_ball() @@ -367,13 +349,8 @@ def testBallDoubleDrain(self): def test_eject_delay(self): # prepare game - 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() - - # start game - self.hit_and_release_switch("s_start") - self.advance_time_and_run() + self.fill_troughs() + self.start_game() self.post_event("enable4") self.advance_time_and_run() self.assertBallNumber(1) @@ -396,13 +373,8 @@ def test_eject_delay(self): def test_only_last(self): # prepare game - 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() - - # start game - self.hit_and_release_switch("s_start") - self.advance_time_and_run() + self.fill_troughs() + self.start_game() self.machine.playfield.add_ball(1) self.advance_time_and_run(10) self.machine.game.balls_in_play = 2 @@ -429,3 +401,33 @@ def test_only_last(self): self.advance_time_and_run(1) self.assertEqual(1, self.machine.playfield.available_balls) self.assertBallNumber(1) + + def test_unlimited_delay(self): + # prepare game + self.fill_troughs() + self.advance_time_and_run() + + # start game + self.start_game() + self.advance_time_and_run(10) + self.assertBallNumber(1) + + # enable ball save + self.post_event("enable5") + + # drain ball + self.drain_ball() + self.advance_time_and_run() + + # ball should not end + self.assertBallNumber(1) + + # no ball yet on playfield + self.assertAvailableBallsOnPlayfield(0) + + self.post_event("eject5") + self.advance_time_and_run() + + # ball 1 continues + self.assertAvailableBallsOnPlayfield(1) + self.assertBallNumber(1) From d810346f77e2ff129dd6a305cd65697791c8213f Mon Sep 17 00:00:00 2001 From: Jan Kantert Date: Mon, 10 Apr 2017 14:34:38 +0200 Subject: [PATCH 5/5] enable halt_on_error on load by default --- mpf/core/file_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mpf/core/file_manager.py b/mpf/core/file_manager.py index 7b29cfabf..13db2dc32 100644 --- a/mpf/core/file_manager.py +++ b/mpf/core/file_manager.py @@ -138,7 +138,7 @@ def get_file_interface(filename): return None @staticmethod - def load(filename, verify_version=False, halt_on_error=False, round_trip=False): + def load(filename, verify_version=False, halt_on_error=True, round_trip=False): """Load a file by name.""" if not FileManager.initialized: FileManager.init()