Updated storyboard mechanics
Updated statemachine Implemented advanced choice mechanics Still testing.
This commit is contained in:
parent
2c85f7ed46
commit
06cbde4179
4 changed files with 333 additions and 368 deletions
|
@ -120,7 +120,7 @@ class PizzaHAL:
|
||||||
# Extract data and sampling rate from file
|
# Extract data and sampling rate from file
|
||||||
# data, fs = sf.read(str(sound), dtype='float32')
|
# data, fs = sf.read(str(sound), dtype='float32')
|
||||||
# self.soundcache[str(sound)] = (data, fs)
|
# self.soundcache[str(sound)] = (data, fs)
|
||||||
self.soundcache[str(sound)] = mx.Sound(sound)
|
self.soundcache[str(sound)] = mx.Sound(str(sound))
|
||||||
|
|
||||||
def init_camera(self):
|
def init_camera(self):
|
||||||
if self.camera is None:
|
if self.camera is None:
|
||||||
|
@ -157,23 +157,19 @@ class PizzaHAL:
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
|
||||||
def move_vert(hal: PizzaHAL, steps: int):
|
def move(hal: PizzaHAL,
|
||||||
|
steps: int,
|
||||||
|
horizontal: bool,
|
||||||
|
**kwargs):
|
||||||
"""
|
"""
|
||||||
Move the motor controlling the vertical scroll a given distance.
|
Move the motor controlling the vertical scroll a given distance.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
hal.send_cmd(SerialCommands.MOTOR_V, steps.to_bytes(2, 'little', signed=True))
|
hal.send_cmd(SerialCommands.MOTOR_H if horizontal else SerialCommands.MOTOR_V,
|
||||||
|
steps.to_bytes(2, 'little', signed=True))
|
||||||
|
|
||||||
|
|
||||||
def move_hor(hal: PizzaHAL, steps: int):
|
def rewind(hal: PizzaHAL, **kwargs):
|
||||||
"""
|
|
||||||
Move the motor controlling the horizontal scroll a given distance.
|
|
||||||
|
|
||||||
"""
|
|
||||||
hal.send_cmd(SerialCommands.MOTOR_H, steps.to_bytes(2, 'little', signed=True))
|
|
||||||
|
|
||||||
|
|
||||||
def rewind(hal: PizzaHAL):
|
|
||||||
"""
|
"""
|
||||||
Rewind both scrolls.
|
Rewind both scrolls.
|
||||||
|
|
||||||
|
@ -181,9 +177,9 @@ def rewind(hal: PizzaHAL):
|
||||||
hal.send_cmd(SerialCommands.REWIND)
|
hal.send_cmd(SerialCommands.REWIND)
|
||||||
|
|
||||||
|
|
||||||
def turn_off(hal: PizzaHAL):
|
def turn_off(hal: PizzaHAL, **kwargs):
|
||||||
"""
|
"""
|
||||||
Turn off everything.
|
Turn off the lights.
|
||||||
"""
|
"""
|
||||||
hal.send_cmd(SerialCommands.BACKLIGHT, 0)
|
hal.send_cmd(SerialCommands.BACKLIGHT, 0)
|
||||||
hal.send_cmd(SerialCommands.FRONTLIGHT, 0)
|
hal.send_cmd(SerialCommands.FRONTLIGHT, 0)
|
||||||
|
@ -223,7 +219,7 @@ def wait_for_input(hal: PizzaHAL,
|
||||||
(8 if green_cb else 0)
|
(8 if green_cb else 0)
|
||||||
|
|
||||||
if sound is not None:
|
if sound is not None:
|
||||||
hal.play_sound(sound)
|
hal.play_sound(str(sound))
|
||||||
|
|
||||||
resp = hal.send_cmd(SerialCommands.USER_INTERACT, bitmask.to_bytes(1, 'little', signed=False), timeout.to_bytes(4, 'little', signed=False))
|
resp = hal.send_cmd(SerialCommands.USER_INTERACT, bitmask.to_bytes(1, 'little', signed=False), timeout.to_bytes(4, 'little', signed=False))
|
||||||
|
|
||||||
|
@ -246,7 +242,14 @@ def wait_for_input(hal: PizzaHAL,
|
||||||
timeout_cb(**kwargs)
|
timeout_cb(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
def light_layer(hal: PizzaHAL, r: float, g: float, b: float, w: float, fade: float = 0.0, **kwargs):
|
def light(hal: PizzaHAL,
|
||||||
|
r: float,
|
||||||
|
g: float,
|
||||||
|
b: float,
|
||||||
|
w: float,
|
||||||
|
fade: float = 0.0,
|
||||||
|
backlight: bool = False,
|
||||||
|
**kwargs):
|
||||||
"""
|
"""
|
||||||
Turn on the light to illuminate the upper scroll
|
Turn on the light to illuminate the upper scroll
|
||||||
|
|
||||||
|
@ -258,30 +261,10 @@ def light_layer(hal: PizzaHAL, r: float, g: float, b: float, w: float, fade: flo
|
||||||
:param steps: int
|
:param steps: int
|
||||||
How many steps for the fade (default: 100)
|
How many steps for the fade (default: 100)
|
||||||
"""
|
"""
|
||||||
hal.send_cmd(SerialCommands.FRONTLIGHT,
|
hal.send_cmd(SerialCommands.BACKLIGHT if backlight else SerialCommands.FRONTLIGHT,
|
||||||
int(r * 255).to_bytes(1, 'little'),
|
|
||||||
int(g * 255).to_bytes(1, 'little'),
|
|
||||||
int(b * 255).to_bytes(1, 'little'),
|
int(b * 255).to_bytes(1, 'little'),
|
||||||
int(w * 255).to_bytes(1, 'little'),
|
|
||||||
int(fade * 1000).to_bytes(4, 'little'))
|
|
||||||
|
|
||||||
|
|
||||||
def backlight(hal: PizzaHAL, r: float, g: float, b: float, w: float, fade: float = 0.0, **kwargs):
|
|
||||||
"""
|
|
||||||
Turn on the backlight
|
|
||||||
|
|
||||||
:param hal: The hardware abstraction object
|
|
||||||
:param fade: float
|
|
||||||
Default 0, time in seconds to fade in or out
|
|
||||||
:param intensity: float
|
|
||||||
Intensity of the light in percent
|
|
||||||
:param steps: int
|
|
||||||
How many steps for the fade (default: 100)
|
|
||||||
"""
|
|
||||||
hal.send_cmd(SerialCommands.BACKLIGHT,
|
|
||||||
int(r * 255).to_bytes(1, 'little'),
|
|
||||||
int(g * 255).to_bytes(1, 'little'),
|
int(g * 255).to_bytes(1, 'little'),
|
||||||
int(b * 255).to_bytes(1, 'little'),
|
int(r * 255).to_bytes(1, 'little'),
|
||||||
int(w * 255).to_bytes(1, 'little'),
|
int(w * 255).to_bytes(1, 'little'),
|
||||||
int(fade * 1000).to_bytes(4, 'little'))
|
int(fade * 1000).to_bytes(4, 'little'))
|
||||||
|
|
||||||
|
@ -295,7 +278,7 @@ def play_sound(hal: PizzaHAL, sound: Any, **kwargs):
|
||||||
"""
|
"""
|
||||||
# Extract data and sampling rate from file
|
# Extract data and sampling rate from file
|
||||||
try:
|
try:
|
||||||
hal.play_sound(sound)
|
hal.play_sound(str(sound))
|
||||||
while mx.get_busy():
|
while mx.get_busy():
|
||||||
pass
|
pass
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
|
|
|
@ -1,248 +1,42 @@
|
||||||
from pizzactrl import storyboard, fs_names
|
from pizzactrl import fs_names
|
||||||
|
from pizzactrl.storyboard import *
|
||||||
|
|
||||||
STORYBOARD = [
|
STORYBOARD = [
|
||||||
storyboard.Chapter(
|
Chapter(
|
||||||
# storyboard.Do(storyboard.Activity.ADVANCE_UP),
|
Do(Activity.ADVANCE_UP,
|
||||||
storyboard.Do(storyboard.Activity.LIGHT_BACK, # Bild 1
|
steps=50),
|
||||||
intensity=1.0, fade=1.0)
|
Do(Activity.LIGHT_BACK, # Bild 1
|
||||||
|
intensity=1.0, fade=1.0),
|
||||||
|
Do(Activity.WAIT_FOR_INPUT,
|
||||||
|
on_blue=Select(Option.CONTINUE),
|
||||||
|
on_red=Select(Option.REPEAT))
|
||||||
),
|
),
|
||||||
storyboard.Chapter(
|
Chapter(
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
Do(Activity.ADVANCE_LEFT,
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
steps=100),
|
||||||
storyboard.Do(storyboard.Activity.WAIT_FOR_INPUT),
|
Do(Activity.ADVANCE_UP,
|
||||||
storyboard.Do(storyboard.Activity.ADVANCE_UP) # Bild 2
|
steps=50),
|
||||||
|
Do(Activity.WAIT_FOR_INPUT,
|
||||||
|
on_blue=Select(Option.CONTINUE),
|
||||||
|
on_red=Select(Option.REPEAT),
|
||||||
|
on_yellow=Select(Option.GOTO, chapter=0),
|
||||||
|
on_green=Select(Option.QUIT))
|
||||||
),
|
),
|
||||||
storyboard.Chapter(
|
Chapter(
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
Do(Activity.ADVANCE_LEFT,
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
steps=-50),
|
||||||
storyboard.Do(storyboard.Activity.ADVANCE_UP), # Bild 3
|
Do(Activity.ADVANCE_UP,
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
steps=-20)
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.ADVANCE_UP), # Bild 4
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.LIGHT_BACK,
|
|
||||||
intensity=0.0),
|
|
||||||
storyboard.Do(storyboard.Activity.WAIT_FOR_INPUT),
|
|
||||||
storyboard.Do(storyboard.Activity.ADVANCE_UP), # Bild 5
|
|
||||||
),
|
),
|
||||||
storyboard.Chapter(
|
Chapter(
|
||||||
storyboard.Do(storyboard.Activity.LIGHT_BACK,
|
Do(Activity.ADVANCE_LEFT,
|
||||||
intensity=1.0),
|
steps=100),
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
Do(Activity.ADVANCE_UP,
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
steps=50),
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
Do(Activity.WAIT_FOR_INPUT,
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
on_blue=Select(Option.CONTINUE),
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
on_red=Select(Option.REPEAT),
|
||||||
sound=fs_names.SFX_REC_AUDIO),
|
on_yellow=Select(Option.GOTO, chapter=0),
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
on_green=Select(Option.QUIT))
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.WAIT_FOR_INPUT),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.SFX_REC_AUDIO),
|
|
||||||
storyboard.Do(storyboard.Activity.RECORD_SOUND,
|
|
||||||
filename=fs_names.REC_NAME,
|
|
||||||
duration=7.0,
|
|
||||||
cache=True),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.SFX_STOP_REC),
|
|
||||||
),
|
|
||||||
storyboard.Chapter(
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.REC_NAME),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.ADVANCE_UP), # Bild 6
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.WAIT_FOR_INPUT),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.SFX_REC_AUDIO),
|
|
||||||
storyboard.Do(storyboard.Activity.RECORD_SOUND,
|
|
||||||
filename=fs_names.REC_CITY_DESC,
|
|
||||||
duration=60.0),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.SFX_STOP_REC),
|
|
||||||
storyboard.Do(storyboard.Activity.ADVANCE_UP) # Bild 7
|
|
||||||
),
|
|
||||||
storyboard.Chapter(
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.LIGHT_BACK,
|
|
||||||
intensity=0.0),
|
|
||||||
storyboard.Do(storyboard.Activity.WAIT_FOR_INPUT),
|
|
||||||
storyboard.Do(storyboard.Activity.TAKE_PHOTO,
|
|
||||||
filename=fs_names.REC_PORTRAIT),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.SFX_SHUTTER)
|
|
||||||
),
|
|
||||||
storyboard.Chapter(
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.WAIT_FOR_INPUT),
|
|
||||||
storyboard.Do(storyboard.Activity.ADVANCE_UP)
|
|
||||||
),
|
|
||||||
storyboard.Chapter(
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.LIGHT_BACK,
|
|
||||||
intensity=1.0),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.LIGHT_BACK,
|
|
||||||
intensity=0., fade=2.0),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.WAIT_FOR_INPUT),
|
|
||||||
storyboard.Do(storyboard.Activity.ADVANCE_UP) # Bild 9
|
|
||||||
),
|
|
||||||
storyboard.Chapter(
|
|
||||||
storyboard.Do(storyboard.Activity.LIGHT_LAYER,
|
|
||||||
intensity=1., fade=0.5),
|
|
||||||
storyboard.Do(storyboard.Activity.LIGHT_BACK,
|
|
||||||
intensity=1., fade=0.5),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.LIGHT_LAYER,
|
|
||||||
intensity=0., fade=1.),
|
|
||||||
storyboard.Do(storyboard.Activity.LIGHT_BACK,
|
|
||||||
intensity=0., fade=1.),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.WAIT_FOR_INPUT),
|
|
||||||
storyboard.Do(storyboard.Activity.ADVANCE_UP) # Bild 10
|
|
||||||
),
|
|
||||||
storyboard.Chapter(
|
|
||||||
storyboard.Do(storyboard.Activity.LIGHT_BACK,
|
|
||||||
intensity=1., fade=1.),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.LIGHT_BACK,
|
|
||||||
intensity=0., fade=1.),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.WAIT_FOR_INPUT),
|
|
||||||
storyboard.Do(storyboard.Activity.ADVANCE_UP) # Bild 11
|
|
||||||
),
|
|
||||||
storyboard.Chapter(
|
|
||||||
storyboard.Do(storyboard.Activity.LIGHT_BACK,
|
|
||||||
intensity=1., fade=1.),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.LIGHT_BACK,
|
|
||||||
intensity=0., fade=1.),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.WAIT_FOR_INPUT),
|
|
||||||
storyboard.Do(storyboard.Activity.ADVANCE_UP) # Bild 12
|
|
||||||
),
|
|
||||||
storyboard.Chapter(
|
|
||||||
storyboard.Do(storyboard.Activity.LIGHT_BACK,
|
|
||||||
intensity=1., fade=.5),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.WAIT_FOR_INPUT),
|
|
||||||
storyboard.Do(storyboard.Activity.ADVANCE_UP) # Bild 13
|
|
||||||
),
|
|
||||||
storyboard.Chapter(
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.LIGHT_BACK,
|
|
||||||
intensity=0., fade=1.),
|
|
||||||
storyboard.Do(storyboard.Activity.WAIT_FOR_INPUT),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.SFX_REC_AUDIO),
|
|
||||||
storyboard.Do(storyboard.Activity.RECORD_SOUND,
|
|
||||||
filename=fs_names.REC_CITY_NAME,
|
|
||||||
duration=7.0),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.SFX_STOP_REC),
|
|
||||||
storyboard.Do(storyboard.Activity.ADVANCE_UP) # Bild 14
|
|
||||||
),
|
|
||||||
storyboard.Chapter(
|
|
||||||
storyboard.Do(storyboard.Activity.LIGHT_BACK,
|
|
||||||
intensity=1., fade=1.),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.WAIT_FOR_INPUT),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.SFX_REC_AUDIO),
|
|
||||||
storyboard.Do(storyboard.Activity.RECORD_SOUND,
|
|
||||||
filename=fs_names.REC_CITY_DESC,
|
|
||||||
duration=60.0),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.SFX_STOP_REC),
|
|
||||||
storyboard.Do(storyboard.Activity.ADVANCE_UP) # Bild 15
|
|
||||||
),
|
|
||||||
storyboard.Chapter(
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.WAIT_FOR_INPUT),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.SFX_REC_AUDIO),
|
|
||||||
storyboard.Do(storyboard.Activity.RECORD_SOUND,
|
|
||||||
filename=fs_names.REC_CITY_DESC,
|
|
||||||
duration=60.0),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.SFX_STOP_REC),
|
|
||||||
storyboard.Do(storyboard.Activity.LIGHT_BACK,
|
|
||||||
intensity=0., fade=1.),
|
|
||||||
storyboard.Do(storyboard.Activity.ADVANCE_UP) # Bild 16
|
|
||||||
),
|
|
||||||
storyboard.Chapter(
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.LIGHT_BACK,
|
|
||||||
intensity=1., fade=1.),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.ADVANCE_UP) # Bild 17
|
|
||||||
),
|
|
||||||
storyboard.Chapter(
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.LIGHT_BACK,
|
|
||||||
intensity=0., fade=1.),
|
|
||||||
storyboard.Do(storyboard.Activity.WAIT_FOR_INPUT),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.SFX_REC_AUDIO),
|
|
||||||
storyboard.Do(storyboard.Activity.RECORD_VIDEO,
|
|
||||||
filename=fs_names.REC_DRAW_CITY,
|
|
||||||
duration=60.0),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.SFX_STOP_REC),
|
|
||||||
|
|
||||||
storyboard.Do(storyboard.Activity.ADVANCE_UP) # Bild 18
|
|
||||||
),
|
|
||||||
storyboard.Chapter(
|
|
||||||
storyboard.Do(storyboard.Activity.LIGHT_BACK,
|
|
||||||
intensity=1., fade=1.),
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.ADVANCE_UP), # Bild 19
|
|
||||||
storyboard.Do(storyboard.Activity.PLAY_SOUND,
|
|
||||||
sound=fs_names.StoryFile('01dummy')),
|
|
||||||
storyboard.Do(storyboard.Activity.LIGHT_BACK,
|
|
||||||
intensity=0., fade=2.)
|
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
|
@ -9,10 +9,11 @@ from enum import Enum, auto
|
||||||
from subprocess import call
|
from subprocess import call
|
||||||
|
|
||||||
from pizzactrl import fs_names, sb_dummy
|
from pizzactrl import fs_names, sb_dummy
|
||||||
from .storyboard import Activity
|
from pizzactrl.hal import ScrollSensor
|
||||||
from .hal_serial import SerialCommunicationError, play_sound, take_photo, record_video, record_sound, turn_off, \
|
from .storyboard import Activity, Select, Option
|
||||||
PizzaHAL, init_camera, init_sounds, wait_for_input, \
|
from .hal_serial import SerialCommunicationError, PizzaHAL, play_sound, take_photo, record_video, record_sound, turn_off, wait_for_input, \
|
||||||
light_layer, backlight, move_vert, move_hor, rewind
|
light, move, rewind
|
||||||
|
from pizzactrl import storyboard
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -50,25 +51,47 @@ def load_sounds():
|
||||||
return soundcache
|
return soundcache
|
||||||
|
|
||||||
|
|
||||||
|
# Map Activities to function calls
|
||||||
|
ACTIVITY_SELECTOR = {
|
||||||
|
Activity.PLAY_SOUND: play_sound,
|
||||||
|
Activity.RECORD_SOUND: record_sound,
|
||||||
|
Activity.RECORD_VIDEO: record_video,
|
||||||
|
Activity.TAKE_PHOTO: take_photo,
|
||||||
|
Activity.LIGHT_LAYER: light,
|
||||||
|
Activity.LIGHT_BACK: light,
|
||||||
|
Activity.ADVANCE_UP: move,
|
||||||
|
Activity.ADVANCE_LEFT: move
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class Statemachine:
|
class Statemachine:
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
story_de: Any=None,
|
story_de: Any=None,
|
||||||
story_en: Any=None,
|
story_en: Any=None,
|
||||||
move: bool = False,
|
move: bool = False,
|
||||||
loop: bool = True):
|
loop: bool = True,
|
||||||
|
test: bool = False):
|
||||||
self.state = State.POWER_ON
|
self.state = State.POWER_ON
|
||||||
self.hal = PizzaHAL()
|
self.hal = PizzaHAL()
|
||||||
|
|
||||||
|
self.chapter = 0
|
||||||
|
self.next_chapter = 0
|
||||||
|
|
||||||
self.story = None
|
self.story = None
|
||||||
self.story_de = story_de
|
self.story_de = story_de
|
||||||
self.story_en = story_en
|
self.story_en = story_en
|
||||||
self.alt = False
|
|
||||||
self.lang = Language.NOT_SET
|
self.lang = Language.NOT_SET
|
||||||
self.move = move
|
|
||||||
self.test = False
|
self.MOVE = move # self.move is reset to this value
|
||||||
|
self.move = self.MOVE
|
||||||
|
|
||||||
|
self.test = test
|
||||||
self.loop = loop
|
self.loop = loop
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
logger.debug(f'Run(state={self.state})')
|
logger.debug(f'Run(state={self.state})')
|
||||||
|
|
||||||
choice = {
|
choice = {
|
||||||
State.POWER_ON: self._power_on,
|
State.POWER_ON: self._power_on,
|
||||||
State.POST: self._post,
|
State.POST: self._post,
|
||||||
|
@ -77,6 +100,7 @@ class Statemachine:
|
||||||
State.REWIND: self._rewind,
|
State.REWIND: self._rewind,
|
||||||
State.IDLE_END: self._idle_end
|
State.IDLE_END: self._idle_end
|
||||||
}
|
}
|
||||||
|
|
||||||
while (self.state is not State.ERROR) and \
|
while (self.state is not State.ERROR) and \
|
||||||
(self.state is not State.SHUTDOWN):
|
(self.state is not State.SHUTDOWN):
|
||||||
choice[self.state]()
|
choice[self.state]()
|
||||||
|
@ -107,40 +131,51 @@ class Statemachine:
|
||||||
Initialize hal callbacks, load sounds
|
Initialize hal callbacks, load sounds
|
||||||
"""
|
"""
|
||||||
logger.debug(f'power on')
|
logger.debug(f'power on')
|
||||||
|
|
||||||
|
# TODO enable lid sensor
|
||||||
# self.hal.lid_sensor.when_pressed = self._lid_open
|
# self.hal.lid_sensor.when_pressed = self._lid_open
|
||||||
# self.hal.lid_sensor.when_released = self._lid_closed
|
# self.hal.lid_sensor.when_released = self._lid_closed
|
||||||
try:
|
|
||||||
self.hal.init_connection()
|
self.hal.init_sounds(load_sounds())
|
||||||
except SerialCommunicationError as e:
|
self.hal.init_camera()
|
||||||
self.state = State.ERROR
|
|
||||||
logger.exception(e)
|
|
||||||
return
|
|
||||||
init_sounds(self.hal, load_sounds())
|
|
||||||
init_camera(self.hal)
|
|
||||||
self.state = State.POST
|
self.state = State.POST
|
||||||
|
|
||||||
def _post(self):
|
def _post(self):
|
||||||
"""
|
"""
|
||||||
Power on self test.
|
Power on self test.
|
||||||
"""
|
"""
|
||||||
logger.debug(f'post')
|
|
||||||
# check scroll positions and rewind if necessary
|
|
||||||
turn_off(self.hal)
|
|
||||||
|
|
||||||
if not os.path.exists(fs_names.USB_STICK):
|
logger.debug(f'post')
|
||||||
|
|
||||||
|
if (not self.test) and (not os.path.exists(fs_names.USB_STICK)):
|
||||||
logger.warning('USB-Stick not found.')
|
logger.warning('USB-Stick not found.')
|
||||||
self.state = State.ERROR
|
self.state = State.ERROR
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# TODO set RPi_HELO pins, wait for response
|
||||||
|
|
||||||
# Callback for start when blue button is held
|
# Callback for start when blue button is held
|
||||||
self.hal.btn_start.when_activated = self._start_or_rewind
|
# self.hal.btn_start.when_activated = self._start_or_rewind
|
||||||
logger.debug('start button callback activated')
|
# logger.debug('start button callback activated')
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.hal.init_connection()
|
||||||
|
except SerialCommunicationError as e:
|
||||||
|
self.state = State.ERROR
|
||||||
|
logger.exception(e)
|
||||||
|
return
|
||||||
|
|
||||||
# play a sound if everything is alright
|
# play a sound if everything is alright
|
||||||
play_sound(self.hal, fs_names.SFX_POST_OK)
|
play_sound(self.hal, fs_names.SFX_POST_OK)
|
||||||
|
|
||||||
self.state = State.IDLE_START
|
if self.test:
|
||||||
logger.debug('idle_start')
|
self.state = State.PLAY
|
||||||
|
logger.debug('play')
|
||||||
|
else:
|
||||||
|
self.state = State.IDLE_START
|
||||||
|
logger.debug('idle_start')
|
||||||
|
|
||||||
|
|
||||||
def _idle_start(self):
|
def _idle_start(self):
|
||||||
"""
|
"""
|
||||||
|
@ -148,24 +183,9 @@ class Statemachine:
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _start_or_rewind(self):
|
|
||||||
"""
|
|
||||||
Callback function.
|
|
||||||
|
|
||||||
If statemachine is in idle state, start playback when start
|
|
||||||
button is pressed (released).
|
|
||||||
|
|
||||||
If statemachine is playing, trigger rewind and start fresh
|
|
||||||
"""
|
|
||||||
if self.state == State.IDLE_START:
|
|
||||||
self.state = State.PLAY
|
|
||||||
return
|
|
||||||
if self.state == State.PLAY:
|
|
||||||
self.state = State.REWIND
|
|
||||||
|
|
||||||
def _play(self):
|
def _play(self):
|
||||||
"""
|
"""
|
||||||
Run the storyboard
|
Select language, then run the storyboard
|
||||||
"""
|
"""
|
||||||
logger.debug(f'play')
|
logger.debug(f'play')
|
||||||
if self.test:
|
if self.test:
|
||||||
|
@ -174,48 +194,134 @@ class Statemachine:
|
||||||
# TODO reenable language selection
|
# TODO reenable language selection
|
||||||
self.story = self.story_en
|
self.story = self.story_en
|
||||||
|
|
||||||
for chapter in iter(self.story):
|
while self.chapter is not None:
|
||||||
logger.debug(f'playing chapter {chapter}')
|
self._play_chapter()
|
||||||
|
self._advance_chapter()
|
||||||
|
|
||||||
|
self.state = State.REWIND
|
||||||
|
|
||||||
|
def _option_callback(self, selection: Select):
|
||||||
|
"""
|
||||||
|
Return a callback for the appropriate option and parameters.
|
||||||
|
Callbacks set the properties of `Statemachine` to determine it's behaviour.
|
||||||
|
"""
|
||||||
|
rewind = selection.values.get('rewind', Option.REPEAT.value['rewind'])
|
||||||
|
next_chapter = selection.values.get('chapter', Option.GOTO.value['chapter'])
|
||||||
|
shutdown = selection.values.get('shutdown', Option.QUIT.value['shutdown'])
|
||||||
|
|
||||||
|
def _continue(**kwargs):
|
||||||
|
"""
|
||||||
|
Continue in the Storyboard. Prepare advancing to the next chapter.
|
||||||
|
"""
|
||||||
|
self.move = self.MOVE
|
||||||
|
if len(self.story) > (self.chapter + 1):
|
||||||
|
self.next_chapter = self.chapter + 1
|
||||||
|
else:
|
||||||
|
self.next_chapter = None
|
||||||
|
|
||||||
|
def _repeat(**kwargs):
|
||||||
|
"""
|
||||||
|
Repeat the current chapter. Do not rewind if the selection says so.
|
||||||
|
"""
|
||||||
|
self.move = rewind
|
||||||
|
self.next_chapter = self.chapter
|
||||||
|
|
||||||
|
def _goto(**kwargs):
|
||||||
|
"""
|
||||||
|
Jump to a specified chapter.
|
||||||
|
"""
|
||||||
|
self.move = self.MOVE
|
||||||
|
self.next_chapter = next_chapter
|
||||||
|
|
||||||
|
def _quit(**kwargs):
|
||||||
|
self.move = self.MOVE
|
||||||
|
self.loop = not shutdown
|
||||||
|
self.next_chapter = None
|
||||||
|
|
||||||
|
return {
|
||||||
|
Option.CONTINUE: _continue,
|
||||||
|
Option.REPEAT: _repeat,
|
||||||
|
Option.GOTO: _goto,
|
||||||
|
Option.QUIT: _quit,
|
||||||
|
None: None
|
||||||
|
}[selection.option]
|
||||||
|
|
||||||
|
def _play_chapter(self):
|
||||||
|
"""
|
||||||
|
Play the chapter specified by self.chapter
|
||||||
|
"""
|
||||||
|
logger.debug(f'playing chapter {self.chapter}')
|
||||||
|
|
||||||
|
if self.chapter < len(self.story):
|
||||||
|
chapter = self.story[self.chapter]
|
||||||
|
|
||||||
while chapter.hasnext():
|
while chapter.hasnext():
|
||||||
act = next(chapter)
|
act = next(chapter)
|
||||||
logger.debug(f'next activity {act.activity}')
|
logger.debug(f'next activity {act.activity}')
|
||||||
if act.activity is Activity.WAIT_FOR_INPUT:
|
if act.activity is Activity.WAIT_FOR_INPUT:
|
||||||
wait_for_input(hal=self.hal,
|
wait_for_input(hal=self.hal,
|
||||||
go_callback=chapter.mobilize,
|
blue_cb = self._option_callback(act.values['on_blue']),
|
||||||
back_callback=chapter.rewind,
|
red_cb = self._option_callback(act.values['on_red']),
|
||||||
to_callback=self._start_or_rewind)
|
yellow_cb = self._option_callback(act.values['on_yellow']),
|
||||||
# elif act.activity is Activity.ADVANCE_UP:
|
green_cb = self._option_callback(act.values['on_green']),
|
||||||
# if chapter.move and self.move:
|
timeout_cb = self._option_callback(act.values['on_timeout']),
|
||||||
# logger.debug(
|
**act.values)
|
||||||
# f'advance({self.hal.motor_ud}, '
|
|
||||||
# f'{self.hal.ud_sensor})')
|
|
||||||
# advance(motor=self.hal.motor_ud,
|
|
||||||
# sensor=self.hal.ud_sensor)
|
|
||||||
# elif not self.move:
|
|
||||||
# play_sound(self.hal, fs_names.StoryFile('stop'))
|
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
{
|
ACTIVITY_SELECTOR[act.activity](self.hal, **act.values)
|
||||||
Activity.PLAY_SOUND: play_sound,
|
|
||||||
Activity.RECORD_SOUND: record_sound,
|
|
||||||
Activity.RECORD_VIDEO: record_video,
|
|
||||||
Activity.TAKE_PHOTO: take_photo,
|
|
||||||
Activity.LIGHT_LAYER: light_layer,
|
|
||||||
Activity.LIGHT_BACK: backlight,
|
|
||||||
# Activity.ADVANCE_UP: move_vert,
|
|
||||||
# Activity.ADVANCE_LEFT: move_hor
|
|
||||||
}[act.activity](self.hal, **act.values)
|
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.exception('Caught KeyError, ignoring...')
|
logger.exception('Caught KeyError, ignoring...')
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
self.next_chapter = self.chapter + 1
|
||||||
|
else:
|
||||||
|
self.next_chapter = None
|
||||||
|
|
||||||
|
def _advance_chapter(self):
|
||||||
|
"""
|
||||||
|
Update chapters and move the scrolls.
|
||||||
|
Update self.chapter to self.next_chapter
|
||||||
|
"""
|
||||||
|
if self.next_chapter is not None:
|
||||||
|
diff = self.next_chapter - self.chapter
|
||||||
|
h_steps = 0
|
||||||
|
v_steps = 0
|
||||||
|
if diff < 0:
|
||||||
|
"""
|
||||||
|
Rewind all chapters up to target
|
||||||
|
"""
|
||||||
|
for ch in self.story[self.next_chapter:self.chapter]:
|
||||||
|
steps = ch.rewind()
|
||||||
|
h_steps += steps['h_steps']
|
||||||
|
v_steps += steps['v_steps']
|
||||||
|
|
||||||
self.state = State.REWIND
|
elif diff > 0:
|
||||||
|
"""
|
||||||
|
Skip all chapters up to target
|
||||||
|
"""
|
||||||
|
for ch in self.story[self.chapter:self.next_chapter]:
|
||||||
|
steps = ch.skip()
|
||||||
|
h_steps += steps['h_steps']
|
||||||
|
v_steps += steps['v_steps']
|
||||||
|
else:
|
||||||
|
"""
|
||||||
|
Rewind current chapter
|
||||||
|
"""
|
||||||
|
steps = self.story[self.chapter].rewind()
|
||||||
|
h_steps = steps['h_steps']
|
||||||
|
v_steps = steps['v_steps']
|
||||||
|
|
||||||
|
if self.move:
|
||||||
|
move(self.hal, h_steps, True)
|
||||||
|
move(self.hal, v_steps, False)
|
||||||
|
|
||||||
|
self.chapter = self.next_chapter
|
||||||
|
|
||||||
def _rewind(self):
|
def _rewind(self):
|
||||||
"""
|
"""
|
||||||
Rewind all scrolls, post-process videos
|
Rewind all scrolls, post-process videos
|
||||||
"""
|
"""
|
||||||
# postprocessing
|
# TODO postprocessing - add sound
|
||||||
logger.debug('Converting video...')
|
logger.debug('Converting video...')
|
||||||
cmdstring = f'MP4Box -add {fs_names.REC_DRAW_CITY} {fs_names.REC_MERGED_VIDEO}'
|
cmdstring = f'MP4Box -add {fs_names.REC_DRAW_CITY} {fs_names.REC_MERGED_VIDEO}'
|
||||||
call([cmdstring], shell=True)
|
call([cmdstring], shell=True)
|
||||||
|
@ -223,6 +329,7 @@ class Statemachine:
|
||||||
logger.debug('Rewinding...')
|
logger.debug('Rewinding...')
|
||||||
if self.move:
|
if self.move:
|
||||||
rewind(self.hal)
|
rewind(self.hal)
|
||||||
|
|
||||||
for chapter in self.story:
|
for chapter in self.story:
|
||||||
chapter.rewind()
|
chapter.rewind()
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,70 @@
|
||||||
from enum import Enum, auto
|
from enum import Enum, auto
|
||||||
|
|
||||||
|
|
||||||
|
class Option(Enum):
|
||||||
|
"""
|
||||||
|
Options can be chosen by the user in WAIT_FOR_INPUT
|
||||||
|
"""
|
||||||
|
CONTINUE = {} # Continue with chapter
|
||||||
|
REPEAT = {'rewind': True} # Repeat chapter from beginning. `rewind=True`: reset scrolls to starting position
|
||||||
|
GOTO = {'chapter': 0} # Jump to chapter number
|
||||||
|
QUIT = {'shutdown': True} # End playback. `shutdown=True` also powers off box
|
||||||
|
|
||||||
|
|
||||||
|
class Select:
|
||||||
|
"""
|
||||||
|
An option instance. Can override the default settings from `Option`s
|
||||||
|
"""
|
||||||
|
def __init__(self, option: Option, **kwargs):
|
||||||
|
self.option = option
|
||||||
|
self.values = {}
|
||||||
|
if option is not None:
|
||||||
|
for key, value in self.option.value.items():
|
||||||
|
self.values[key] = kwargs.get(key, value)
|
||||||
|
|
||||||
|
|
||||||
class Activity(Enum):
|
class Activity(Enum):
|
||||||
WAIT_FOR_INPUT = {'steps': 0}
|
"""
|
||||||
PLAY_SOUND = {'sound': None}
|
Things the box can do
|
||||||
RECORD_SOUND = {'duration': 0.0, 'filename': '', 'cache': False}
|
"""
|
||||||
RECORD_VIDEO = {'duration': 0.0, 'filename': ''}
|
WAIT_FOR_INPUT = {'on_blue': Select(Option.CONTINUE),
|
||||||
TAKE_PHOTO = {'filename': ''}
|
'on_red': Select(Option.REPEAT),
|
||||||
ADVANCE_UP = {'speed': 0.3, 'direction': True, 'steps': 100}
|
'on_yellow': Select(None),
|
||||||
ADVANCE_LEFT = {'speed': 0.3, 'direction': True, 'steps': 200} # TODO set right number of steps
|
'on_green': Select(None),
|
||||||
LIGHT_LAYER = {'intensity': 1.0, 'fade': 0.0, 'layer': True}
|
'on_timeout': Select(Option.QUIT),
|
||||||
LIGHT_BACK = {'intensity': 1.0, 'fade': 0.0}
|
'sound': None,
|
||||||
|
'timeout': 0}
|
||||||
|
PLAY_SOUND = {'sound': None}
|
||||||
|
RECORD_SOUND = {'duration': 10.0,
|
||||||
|
'filename': '',
|
||||||
|
'cache': False}
|
||||||
|
RECORD_VIDEO = {'duration': 60.0,
|
||||||
|
'filename': ''}
|
||||||
|
TAKE_PHOTO = {'filename': ''}
|
||||||
|
ADVANCE_UP = {'steps': 100, # TODO set right number of steps
|
||||||
|
'direction': True,
|
||||||
|
'horizontal': False}
|
||||||
|
ADVANCE_LEFT = {'steps': 200, # TODO set right number of steps
|
||||||
|
'direction': True,
|
||||||
|
'horizontal': True}
|
||||||
|
LIGHT_LAYER = {'r': 0,
|
||||||
|
'g': 0,
|
||||||
|
'b': 0,
|
||||||
|
'w': 1.0,
|
||||||
|
'fade': 1.0,
|
||||||
|
'backlight': False}
|
||||||
|
LIGHT_BACK = {'r': 0,
|
||||||
|
'g': 0,
|
||||||
|
'b': 0,
|
||||||
|
'w': 1.0,
|
||||||
|
'fade': 1.0,
|
||||||
|
'backlight': True}
|
||||||
|
|
||||||
|
|
||||||
class Do:
|
class Do:
|
||||||
|
"""
|
||||||
|
An activity instance. Can override the default settings from `Activity`s
|
||||||
|
"""
|
||||||
def __init__(self, activity: Activity, **kwargs):
|
def __init__(self, activity: Activity, **kwargs):
|
||||||
self.activity = activity
|
self.activity = activity
|
||||||
self.values = {}
|
self.values = {}
|
||||||
|
@ -23,33 +74,63 @@ class Do:
|
||||||
|
|
||||||
class Chapter:
|
class Chapter:
|
||||||
"""
|
"""
|
||||||
A logical storyboard entity, which can be replayed (rewind to start).
|
A logical storyboard entity, which can be replayed (rewind to start)
|
||||||
|
or skipped (do all movements at once).
|
||||||
|
|
||||||
Keeps track of advanced steps on the scrolls.
|
Keeps track of advanced steps on the scrolls.
|
||||||
"""
|
"""
|
||||||
def __init__(self, *activities):
|
def __init__(self, *activities):
|
||||||
self.activities = activities
|
self.activities = activities
|
||||||
self.pos = 0
|
self.index = 0
|
||||||
self.move = True
|
self.h_pos = 0
|
||||||
self.move_ud = 0
|
self.v_pos = 0
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __next__(self):
|
def __next__(self):
|
||||||
if self.pos >= len(self.activities):
|
if self.index >= len(self.activities):
|
||||||
raise StopIteration
|
raise StopIteration
|
||||||
act = self.activities[self.pos]
|
|
||||||
self.pos += 1
|
act = self.activities[self.index]
|
||||||
|
self._update_pos(act)
|
||||||
return act
|
return act
|
||||||
|
|
||||||
|
def _update_pos(self, act: Activity):
|
||||||
|
"""
|
||||||
|
Update the positions from the activity.
|
||||||
|
Implicitly increments the index.
|
||||||
|
"""
|
||||||
|
self.index += 1
|
||||||
|
if act.activity is Activity.ADVANCE_UP:
|
||||||
|
self.v_pos += act.values.get('steps', 0)
|
||||||
|
elif act.activity is Activity.ADVANCE_LEFT:
|
||||||
|
self.h_pos += act.values.get('steps', 0)
|
||||||
|
|
||||||
def hasnext(self):
|
def hasnext(self):
|
||||||
return self.pos < len(self.activities)
|
"""
|
||||||
|
Returns True if the chapter has more activities
|
||||||
|
"""
|
||||||
|
return self.index < len(self.activities)
|
||||||
|
|
||||||
def rewind(self, **kwargs):
|
def rewind(self, **kwargs):
|
||||||
self.move = False
|
"""
|
||||||
self.pos = 0
|
Reset the position to zero. Return how many steps are needed to rewind the scrolls
|
||||||
|
"""
|
||||||
|
self.index = 0
|
||||||
|
h_pos = self.h_pos
|
||||||
|
v_pos = self.v_pos
|
||||||
|
self.h_pos = 0
|
||||||
|
self.v_pos = 0
|
||||||
|
return {'h_steps': -h_pos, 'v_steps': -v_pos}
|
||||||
|
|
||||||
def mobilize(self, **kwargs):
|
def skip(self, **kwargs):
|
||||||
self.move = True
|
"""
|
||||||
|
Skip chapter. Returns all movements necessary to advance scrolls.
|
||||||
|
"""
|
||||||
|
h_pos = self.h_pos
|
||||||
|
v_pos = self.v_pos
|
||||||
|
for act in self.activities[self.index:]:
|
||||||
|
self._update_pos(act)
|
||||||
|
return {'h_steps': self.h_pos - h_pos, 'v_steps': self.v_pos - v_pos}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue