diff --git a/mpf/core/config_spec.py b/mpf/core/config_spec.py index 6fe041d40..45591261e 100644 --- a/mpf/core/config_spec.py +++ b/mpf/core/config_spec.py @@ -1068,7 +1068,7 @@ end_value: single|template_int|None direction: single|str|up max_value: single|int|None - tick_interval: single|ms|1s + tick_interval: single|template_secs|1s start_running: single|bool|False control_events: list|subconfig(timer_control_events)|None restart_on_complete: single|bool|False diff --git a/mpf/core/config_validator.py b/mpf/core/config_validator.py index e1052bef7..fef7cf6db 100644 --- a/mpf/core/config_validator.py +++ b/mpf/core/config_validator.py @@ -36,6 +36,7 @@ def __init__(self, machine): "template_float": self._validate_type_template_float, "template_int": self._validate_type_template_int, "template_bool": self._validate_type_template_bool, + "template_secs": self._validate_type_template_secs, "boolean": self._validate_type_bool, "ms": self._validate_type_ms, "secs": self._validate_type_secs, @@ -372,6 +373,20 @@ def _validate_type_template_float(self, item, validation_failure_info): return self.machine.placeholder_manager.build_float_template(item) + def _validate_type_template_secs(self, item, validation_failure_info): + if item is None: + return None + if not isinstance(item, (str, int)): + self.validation_error(item, validation_failure_info, "Template has to be string/int.") + + # try to convert to float. if we fail it will be a template + try: + item = Util.string_to_secs(item) + except ValueError: + pass + + return self.machine.placeholder_manager.build_float_template(item) + def _validate_type_template_int(self, item, validation_failure_info): if item is None: return None diff --git a/mpf/devices/timer.py b/mpf/devices/timer.py index 675c6fd50..55792e80e 100644 --- a/mpf/devices/timer.py +++ b/mpf/devices/timer.py @@ -50,23 +50,15 @@ def _initialize(self): self.ticks_remaining = 0 self.max_value = self.config['max_value'] self.direction = self.config['direction'].lower() - self.tick_secs = self.config['tick_interval'] / 1000.0 + self.tick_secs = None self.timer = None # type: PeriodicTask self.event_keys = list() # type: List[EventHandlerKey] self.delay = DelayManager(self.machine.delayRegistry) - try: - self.end_value = self.config['end_value'].evaluate([]) - except AttributeError: - self.end_value = None - - if self.direction == 'down' and not self.end_value: - self.end_value = 0 # need it to be 0 not None - - self.start_value = self.config['start_value'].evaluate([]) self.restart_on_complete = self.config['restart_on_complete'] - - self.ticks = self.start_value + self.end_value = None + self.start_value = None + self.ticks = None if self.config['debug']: self.configure_logging('Timer.' + self.name, @@ -91,6 +83,19 @@ def _initialize(self): def device_loaded_in_mode(self, mode: Mode, player: Player): """Set up control events when mode is loaded.""" del mode + self.tick_secs = self.config['tick_interval'].evaluate([]) + + try: + self.end_value = self.config['end_value'].evaluate([]) + except AttributeError: + self.end_value = None + + if self.direction == 'down' and not self.end_value: + self.end_value = 0 # need it to be 0 not None + + self.start_value = self.config['start_value'].evaluate([]) + self.ticks = self.start_value + self.player = player if self.config['control_events']: self._setup_control_events(self.config['control_events']) @@ -142,7 +147,7 @@ def _setup_control_events(self, event_list): elif entry['action'] == 'reset_tick_interval': handler = self.set_tick_interval - kwargs = {'timer_value': self.config['tick_interval'] / 1000.0} + kwargs = {'timer_value': self.config['tick_interval'].evaluate([])} else: raise AssertionError("Invalid control_event action {} in mode". diff --git a/mpf/tests/test_Timer.py b/mpf/tests/test_Timer.py index 547d4fe46..1b318587e 100644 --- a/mpf/tests/test_Timer.py +++ b/mpf/tests/test_Timer.py @@ -325,3 +325,32 @@ def test_interrupt_timer_by_mode_stop_with_player(self): self.advance_time_and_run(20) self.assertEqual(3, self.tick) self.assertFalse(self.started) + + def test_mode_timer_with_player_var(self): + # add a fake player + self.start_game() + + # start mode. no player vars + self.mock_event("timer_timer_player_var_complete") + self.machine.events.post('start_mode_with_timers') + self.advance_time_and_run(.1) + + self.assertEventCalled("timer_timer_player_var_complete") + self.machine.events.post('stop_mode_with_timers') + self.advance_time_and_run(.1) + + # set player vars. timer should run 5s + self.machine.game.player.start = 2 + self.machine.game.player.end = 7 + + self.machine.log.debug("START") + self.mock_event("timer_timer_player_var_complete") + self.machine.events.post('start_mode_with_timers') + self.advance_time_and_run(4.5) + self.machine.log.debug("END") + self.assertEventNotCalled("timer_timer_player_var_complete") + + self.advance_time_and_run(0.6) + + self.assertEventCalled("timer_timer_player_var_complete") + self.machine.events.post('stop_mode_with_timers') \ No newline at end of file