Skip to content

Commit

Permalink
initial checkin of achievement groups
Browse files Browse the repository at this point in the history
  • Loading branch information
toomanybrians committed Oct 13, 2016
1 parent 7e09ff8 commit 496aa0e
Show file tree
Hide file tree
Showing 4 changed files with 218 additions and 13 deletions.
17 changes: 17 additions & 0 deletions mpf/core/config_spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,20 @@
level_y: single|int|0
level_z: single|int|1
number: single|str|
achievement_groups:
__valid_in__: mode
achievements: list|machine(achievements)|
enable_events: dict|str:ms|None
disable_events: dict|str:ms|None
start_selected_events: dict|str:ms|None
select_random_achievement_events: dict|str:ms|None
rotate_right_events: dict|str:ms|None
rotate_left_events: dict|str:ms|None
events_when_all_complete: list|str|None
events_when_no_more_enabled: list|str|None
events_when_enabled: list|str|None
show_tokens: dict|str:str|None
show_when_enabled: single|str|None
achievements:
__valid_in__: mode
enable_events: dict|str:ms|None
Expand All @@ -22,16 +36,19 @@
disable_events: dict|str:ms|None
stop_events: dict|str:ms|None
reset_events: dict|str:ms|None
select_events: dict|str:ms|None
events_when_enabled: list|str|None
events_when_started: list|str|None
events_when_completed: list|str|None
events_when_stopped: list|str|None
events_when_disabled: list|str|None
events_when_selected: list|str|None
show_when_enabled: single|str|None
show_when_started: single|str|None
show_when_completed: single|str|None
show_when_stopped: single|str|None
show_when_disabled: single|str|None
show_when_selected: single|str|None
show_tokens: dict|str:str|None
restart_on_next_ball_when_started: single|bool|True
enable_on_next_ball_when_enabled: single|bool|True
Expand Down
59 changes: 46 additions & 13 deletions mpf/devices/achievement.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ class Achievement(ModeDevice):

"""An achievement in a pinball machine.
It is tracked per player and can automatically restore state on the next ball.
It is tracked per player and can automatically restore state on the next
ball.
"""

config_section = 'achievements'
Expand All @@ -22,6 +23,10 @@ def __init__(self, machine, name):
self._mode = None
self._show = None

@property
def state(self):
return self._state

@property
def _state(self):
return self._player.achievements[self.name]
Expand All @@ -30,41 +35,59 @@ def _state(self):
def _state(self, value):
self._player.achievements[self.name] = value

def validate_and_parse_config(self, config: dict, is_mode_config: bool) -> dict:

config = super().validate_and_parse_config(config, is_mode_config)

states = ['disabled', 'enabled', 'started', 'stopped', 'selected',
'completed']

for state in states:
if not config['events_when_{}'.format(state)]:
config['events_when_{}'.format(state)] = [
"achievement_{}_state_{}".format(self.name, state)]

return config

def enable(self, **kwargs):
"""Enable the achievement.
It can only start if it was enabled before.
"""
del kwargs
if self._state == "disabled":
if self._state in ("disabled", "selected"):
self._state = "enabled"
self._run_state()

def start(self, **kwargs):
"""Start achievement."""
del kwargs
if self._state == "enabled" or (self.config['restart_after_stop_possible'] and self._state == "stopped"):
if self._state in ("enabled", "selected") or (
self.config['restart_after_stop_possible'] and
self._state == "stopped"):
self._state = "started"
self._run_state()

def complete(self, **kwargs):
"""Complete achievement."""
del kwargs
if self._state == "started":
if self._state in ("started", "selected"):
self._state = "completed"
self._run_state()

def stop(self, **kwargs):
"""Stop achievement."""
del kwargs
if self._state == "started":
if self._state in ("started", "selected"):
self._state = "stopped"
self._run_state()

def disable(self, **kwargs):
"""Disable achievement."""
del kwargs
if self._state == "enabled" or (self.config['restart_after_stop_possible'] and self._state == "stopped"):
if self._state in ("enabled", "selected") or (
self.config['restart_after_stop_possible'] and
self._state == "stopped"):
self._state = "disabled"
self._run_state()

Expand All @@ -82,14 +105,22 @@ def reset(self, **kwargs):

self._run_state()

def select(self, **kwargs):
"""Highlight (select) this achievement"""
del kwargs

if not self._player:
return

if self._state == 'enabled':
self._state = 'selected'

self._run_state()

def _run_state(self, restore=False):
"""Run shows and post events for current step."""
if self.config['events_when_' + self._state]:
events = self.config['events_when_' + self._state]
else:
events = ["achievement_{}_state_{}".format(self.name, self._state)]

for event in events:
for event in self.config['events_when_{}'.format(self._state)]:
self.machine.events.post(event, restore=restore)
'''event: achievement_(name)_state_(state)
desc: Achievement (name) changed to state (state).
Expand Down Expand Up @@ -132,9 +163,11 @@ def device_added_to_mode(self, mode: Mode, player: Player):
self._restore_state()

def _restore_state(self):
if self._state == "started" and not self.config['restart_on_next_ball_when_started']:
if self._state == "started" and not (
self.config['restart_on_next_ball_when_started']):
self._state = "stopped"
elif self._state == "enabled" and not self.config['enable_on_next_ball_when_enabled']:
elif self._state == "enabled" and not (
self.config['enable_on_next_ball_when_enabled']):
self._state = "disabled"

self._run_state(restore=True)
Expand Down
153 changes: 153 additions & 0 deletions mpf/devices/achievement_group.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
"""An achievement group which manages and groups achievements."""
from collections import deque

from random import choice

from mpf.core.mode import Mode
from mpf.core.mode_device import ModeDevice
from mpf.core.player import Player


class AchievementGroup(ModeDevice):
"""An achievement group in a pinball machine.
It is tracked per player and can automatically restore state on the next
ball.
"""

config_section = 'achievement_groups'
collection = 'achievement_groups'
class_label = 'achievement_group'

def __init__(self, machine, name):
"""Initialize achievement."""
super().__init__(machine, name)

self._mode = None
self._show = None

self._enabled = False
self._complete_achievements = set()

def enable(self, **kwargs):
self._enabled = True

show = self.config['show_when_enabled']

self._stop_show()

if show:
self._show = self.machine.shows[show].play(
priority=self._mode.priority,
loops=-1,
show_tokens=self.config['show_tokens'])

for e in self.config['events_when_enabled']:
self.machine.events.post(e)

def disable(self, **kwargs):
self._stop_show()
self._enabled = False

def _stop_show(self):
if self._show:
self._show.stop()
self._show = None

def start_selected(self, **kwargs):
if not self._enabled:
return

for ach in [x for x in self.config['achievements'] if
x.state == 'selected']:
ach.start()

def rotate_right(self, reverse=False, **kwargs):
achievements = ([x for x in self.config['achievements'] if
x.state in ('enabled', 'selected')])

for index, a in enumerate(achievements):
if a.state == 'selected':
a.enable()

if not reverse:
try:
achievements[index+1].select()
except IndexError:
achievements[0].select()
else:
achievements[index-1].select()

return

def rotate_left(self, **kwargs):
self.rotate_right(reverse=True)

def no_more_enabled(self):
for e in self.config['events_when_no_more_enabled']:
self.machine.events.post(e)

def all_complete(self):
for e in self.config['events_when_all_complete']:
self.machine.events.post(e)

def select_random_achievement(self, **kwargs):
try:
ach = choice([x for x in self.config['achievements'] if
x.state == 'enabled' or
(x.state == 'stopped' and
x.config['restart_after_stop_possible'])])
ach.select()

except IndexError:
self.no_more_enabled()

def _member_state_changed(self, achievement, **kwargs):
del kwargs

state = achievement.state

if state == 'completed':
self._complete_achievements.add(achievement)
else:
self._complete_achievements.discard(achievement)

self._check_for_all_complete()

def _check_for_all_complete(self):
if len(self._complete_achievements) == len(
self.config['achievements']):
self.all_complete()

def device_added_to_mode(self, mode: Mode, player: Player):
"""Load device on mode start and restore state.
Args:
mode: mode which was contains the device
player: player which is currently active
"""
super().device_added_to_mode(mode, player)

self._mode = mode

states = ['disabled', 'enabled', 'started', 'stopped', 'selected',
'completed']

for ach in self.config['achievements']:

for state in states:
mode.add_mode_event_handler(
ach.config['events_when_{}'.format(state)][0],
self._member_state_changed,
achievement=ach)

def device_removed_from_mode(self, mode: Mode):
"""Mode ended.
Args:
mode: mode which stopped
"""
del mode
self._mode = None
if self._show:
self._show.stop()
2 changes: 2 additions & 0 deletions mpf/mpfconfig.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ mpf:
- mpf.devices.accelerometer.Accelerometer
- mpf.devices.servo.Servo
- mpf.devices.achievement.Achievement
- mpf.devices.achievement_group.AchievementGroup
- mpf.devices.physical_dmd.PhysicalDmd
- mpf.devices.physical_rgb_dmd.PhysicalRgbDmd
- mpf.devices.led_group.LedStrip
Expand Down Expand Up @@ -160,6 +161,7 @@ mpf:
- switches
- timers
- achievements
- achievement_groups

# Default settings for machines. All can be overridden

Expand Down

0 comments on commit 496aa0e

Please sign in to comment.