diff --git a/mpf/core/config_spec.py b/mpf/core/config_spec.py index ac162c2a8..688119a19 100644 --- a/mpf/core/config_spec.py +++ b/mpf/core/config_spec.py @@ -281,6 +281,10 @@ switch: single|machine(switches)|None value: single|float|0.25 type: single|str|money + events: + event: single|str|None + credits: single|float|0.25 + type: single|str|replay pricing_tiers: price: single|float|.50 credits: single|int|1 diff --git a/mpf/core/placeholder_manager.py b/mpf/core/placeholder_manager.py index 0917cd6b0..693aede8e 100644 --- a/mpf/core/placeholder_manager.py +++ b/mpf/core/placeholder_manager.py @@ -254,8 +254,11 @@ def _eval_unary_op(self, node, variables): def _eval_compare(self, node, variables): if len(node.ops) > 1: raise AssertionError("Only single comparisons are supported.") - return comparisons[type(node.ops[0])](self._eval(node.left, variables), - self._eval(node.comparators[0], variables)) + try: + return comparisons[type(node.ops[0])](self._eval(node.left, variables), + self._eval(node.comparators[0], variables)) + except TypeError as e: + raise ValueError("Comparison failed: {}".format(e)) def _eval_bool_op(self, node, variables): result = self._eval(node.values[0], variables) diff --git a/mpf/modes/credits/code/credits.py b/mpf/modes/credits/code/credits.py index e95d303a9..82052ba2b 100644 --- a/mpf/modes/credits/code/credits.py +++ b/mpf/modes/credits/code/credits.py @@ -59,7 +59,7 @@ def mode_start(self, **kwargs): def mode_stop(self, **kwargs): """Stop mode.""" self._set_free_play_string() - self._disable_credit_switch_handlers() + self._disable_credit_handlers() def _calculate_credit_units(self): # "credit units" are how we handle fractional credits (since most @@ -106,7 +106,7 @@ def _calculate_credit_units(self): self.credit_units_per_game = int(price_per_game / self.credit_unit) - self.debug_log("Credit units per game: %s", self.credit_units_per_game) + self.info_log("Credit units per game: %s", self.credit_units_per_game) def _calculate_pricing_tiers(self): # pricing tiers are calculated with a set of tuples which indicate the @@ -184,7 +184,7 @@ def enable_credit_play(self, post_event=True, **kwargs): self._update_credit_strings() - self._enable_credit_switch_handlers() + self._enable_credit_handlers() # prevent duplicate handlers self._remove_event_handlers() @@ -226,7 +226,7 @@ def enable_free_play(self, post_event=True, **kwargs): self._remove_event_handlers() - self._disable_credit_switch_handlers() + self._disable_credit_handlers() self._update_credit_strings() @@ -257,11 +257,11 @@ def _player_add_request(self, **kwargs): del kwargs if (self._get_credit_units() >= self.credit_units_per_game): - self.debug_log("Received request to add player. Request Approved") + self.info_log("Received request to add player. Request Approved. Sufficient credits available.") return True else: - self.debug_log("Received request to add player. Request Denied") + self.info_log("Received request to add player. Request Denied. Not enough credits available.") self.machine.events.post("not_enough_credits") '''event: not_enough_credits desc: A player has pushed the start button, but the game is not set @@ -274,11 +274,11 @@ def _request_to_start_game(self, **kwargs): del kwargs if (self._get_credit_units() >= self.credit_units_per_game): - self.debug_log("Received request to start game. Request Approved") + self.info_log("Received request to start game. Request Approved. Sufficient credits available.") return True else: - self.debug_log("Received request to start game. Request Denied") + self.info_log("Received request to start game. Request Denied. Not enough credits available.") self.machine.events.post("not_enough_credits") # event docstring covered in _player_add_request() method return False @@ -289,14 +289,14 @@ def _player_added(self, **kwargs): self.credit_units_per_game) if new_credit_units < 0: - self.log.warning("Somehow credit units went below 0?!? Resetting " + self.warning_log("Somehow credit units went below 0?!? Resetting " "to 0.") new_credit_units = 0 self.machine.set_machine_var('credit_units', new_credit_units) self._update_credit_strings() - def _enable_credit_switch_handlers(self): + def _enable_credit_handlers(self): for switch_settings in self.credits_config['switches']: self.machine.switch_controller.add_switch_handler( switch_name=switch_settings['switch'].name, @@ -309,24 +309,41 @@ def _enable_credit_switch_handlers(self): switch_name=switch.name, callback=self._service_credit_callback) - def _disable_credit_switch_handlers(self): + for event_settings in self.credits_config['events']: + self.machine.events.add_handler( + event=event_settings['event'], + handler=self._credit_event_callback, + credits=event_settings['credits'], + audit_class=event_settings['type']) + + def _disable_credit_handlers(self): for switch_settings in self.credits_config['switches']: self.machine.switch_controller.remove_switch_handler( switch_name=switch_settings['switch'].name, callback=self._credit_switch_callback) + self.machine.events.remove_handler(self._credit_event_callback) + for switch in self.credits_config['service_credits_switch']: self.machine.switch_controller.remove_switch_handler( switch_name=switch.name, callback=self._service_credit_callback) def _credit_switch_callback(self, value, audit_class): + self.info_log("Credit switch hit. Credit Added. Value: %s. Type: %s", value, audit_class) self._add_credit_units(credit_units=value / self.credit_unit) self._audit(value, audit_class) self._reset_timeouts() + def _credit_event_callback(self, credits, audit_class, **kwargs): + del kwargs + self.info_log("Credit event hit. Credit Added. Credits: %s. Type: %s", credits, audit_class) + self._add_credit_units(credit_units=credits * self.credit_units_per_game, price_tiering=False) + self._audit(credits, audit_class) + self._reset_timeouts() + def _service_credit_callback(self): - self.debug_log("Service Credit Added") + self.info_log("Service Credit Added. Value: 1.") self.add_credit(price_tiering=False) self._audit(1, 'service_credit') @@ -351,7 +368,7 @@ def _add_credit_units(self, credit_units, price_tiering=True): self.credit_units_per_game) if max_credit_units and total_credit_units > max_credit_units: - self.debug_log("Max credits reached") + self.info_log("Max credits reached.") self._update_credit_strings() self.machine.events.post('max_credits_reached') '''event: max_credits_reached @@ -360,7 +377,7 @@ def _add_credit_units(self, credit_units, price_tiering=True): self.machine.set_machine_var('credit_units', max_credit_units) if max_credit_units <= 0 or max_credit_units > previous_credit_units: - self.debug_log("Credit units added") + self.info_log("Credit units added") self.machine.set_machine_var('credit_units', total_credit_units) self._update_credit_strings() self.machine.events.post('credits_added') @@ -380,7 +397,7 @@ def add_credit(self, price_tiering=True): def _reset_pricing_tier_credits(self): if not self.reset_pricing_tier_count_this_game: - self.debug_log("Resetting pricing tier credit count") + self.info_log("Resetting pricing tier credit count.") self.credit_units_for_pricing_tiers = 0 self.reset_pricing_tier_count_this_game = True @@ -439,7 +456,7 @@ def _audit(self, value, audit_class): def _game_started(self, **kwargs): del kwargs - self.debug_log("Removing credit clearing delays") + self.debug_log("Removing credit clearing delays.") self.delay.remove('clear_fractional_credits') self.delay.remove('clear_all_credits') @@ -465,7 +482,7 @@ def _game_ended(self, **kwargs): self.reset_pricing_tier_count_this_game = False def _clear_fractional_credits(self): - self.debug_log("Clearing fractional credits") + self.info_log("Clearing fractional credits.") credit_units = self._get_credit_units() credit_units -= credit_units % self.credit_units_per_game @@ -476,6 +493,6 @@ def _clear_fractional_credits(self): def clear_all_credits(self, **kwargs): """Clear all credits.""" del kwargs - self.debug_log("Clearing all credits") + self.info_log("Clearing all credits.") self.machine.set_machine_var('credit_units', 0) self._update_credit_strings() diff --git a/mpf/tests/MpfTestCase.py b/mpf/tests/MpfTestCase.py index 477dc0df1..7036dd395 100644 --- a/mpf/tests/MpfTestCase.py +++ b/mpf/tests/MpfTestCase.py @@ -278,6 +278,9 @@ def _wait_for_start(self, init, timeout): if time.time() > start + timeout: raise AssertionError("Start took more than {}s".format(timeout)) + # trigger exception if there was one + init.result() + def _mock_event_handler(self, event_name, **kwargs): self._last_event_kwargs[event_name] = kwargs self._events[event_name] += 1 diff --git a/mpf/tests/machine_files/credits/config/config.yaml b/mpf/tests/machine_files/credits/config/config.yaml index 4dcbcb0c6..770c7ae19 100644 --- a/mpf/tests/machine_files/credits/config/config.yaml +++ b/mpf/tests/machine_files/credits/config/config.yaml @@ -23,6 +23,17 @@ coils: c_eject: number: +settings: + replay_score: + label: Replay Score + values: + 500000: "500000 (default)" + 1000000: "1000000" + 1500000: "1500000" + default: 500000 + key_type: int + sort: 100 + credits: max_credits: 12 free_play: no @@ -37,6 +48,10 @@ credits: - switch: s_right_coin type: money value: 1 + events: + - event: game_ending{current_player.score > settings.replay_score} + type: award + credits: 1 pricing_tiers: - price: .50 credits: 1 diff --git a/mpf/tests/test_CreditsMode.py b/mpf/tests/test_CreditsMode.py index 9e88d1a5a..a3a56e5ca 100644 --- a/mpf/tests/test_CreditsMode.py +++ b/mpf/tests/test_CreditsMode.py @@ -136,6 +136,33 @@ def testCredits(self): self.machine_run() self.assertEqual("CREDITS 3", self.machine.get_machine_var('credits_string')) + def testReplay(self): + # add coins + self.hit_and_release_switch("s_left_coin") + self.hit_and_release_switch("s_left_coin") + self.advance_time_and_run() + self.assertEqual("CREDITS 1", self.machine.get_machine_var('credits_string')) + # start game + self.start_game(True) + + self.assertEqual("CREDITS 0", self.machine.get_machine_var('credits_string')) + # no replay + self.stop_game() + + # try again + self.hit_and_release_switch("s_left_coin") + self.hit_and_release_switch("s_left_coin") + self.advance_time_and_run() + self.assertEqual("CREDITS 1", self.machine.get_machine_var('credits_string')) + self.start_game(True) + + # score 600k + self.machine.game.player.score = 600000 + + # replay credit on game end + self.stop_game() + self.assertEqual("CREDITS 1", self.machine.get_machine_var('credits_string')) + def testMorePlayers(self): self.assertTrue(self.machine.mode_controller.is_active('credits')) self.assertEqual("CREDITS 0", self.machine.get_machine_var('credits_string'))