bastd.tutorial

Wrangles the game tutorial sequence.

   1# Released under the MIT License. See LICENSE for details.
   2#
   3"""Wrangles the game tutorial sequence."""
   4
   5# Not too concerned with keeping this old module pretty;
   6# don't expect to be revisiting it.
   7# pylint: disable=too-many-branches
   8# pylint: disable=too-many-statements
   9# pylint: disable=too-many-lines
  10# pylint: disable=missing-function-docstring, missing-class-docstring
  11# pylint: disable=invalid-name
  12# pylint: disable=too-many-locals
  13# pylint: disable=unused-argument
  14# pylint: disable=unused-variable
  15
  16from __future__ import annotations
  17
  18import math
  19from typing import TYPE_CHECKING
  20
  21import _ba
  22import ba
  23from bastd.actor import spaz as basespaz
  24
  25if TYPE_CHECKING:
  26    from typing import Any, Callable, Sequence
  27
  28
  29def _safesetattr(node: ba.Node | None, attr: str, value: Any) -> None:
  30    if node:
  31        setattr(node, attr, value)
  32
  33
  34class ButtonPress:
  35
  36    def __init__(self,
  37                 button: str,
  38                 delay: int = 0,
  39                 release: bool = True,
  40                 release_delay: int = 0):
  41        self._button = button
  42        self._delay = delay
  43        self._release = release
  44        self._release_delay = release_delay
  45
  46    def run(self, a: TutorialActivity) -> None:
  47        s = a.current_spaz
  48        assert s is not None
  49        img: ba.Node | None
  50        release_call: Callable[[], None] | None
  51        color: Sequence[float] | None
  52        if self._button == 'punch':
  53            call = s.on_punch_press
  54            release_call = s.on_punch_release
  55            img = a.punch_image
  56            color = a.punch_image_color
  57        elif self._button == 'jump':
  58            call = s.on_jump_press
  59            release_call = s.on_jump_release
  60            img = a.jump_image
  61            color = a.jump_image_color
  62        elif self._button == 'bomb':
  63            call = s.on_bomb_press
  64            release_call = s.on_bomb_release
  65            img = a.bomb_image
  66            color = a.bomb_image_color
  67        elif self._button == 'pickUp':
  68            call = s.on_pickup_press
  69            release_call = s.on_pickup_release
  70            img = a.pickup_image
  71            color = a.pickup_image_color
  72        elif self._button == 'run':
  73            call = ba.Call(s.on_run, 1.0)
  74            release_call = ba.Call(s.on_run, 0.0)
  75            img = None
  76            color = None
  77        else:
  78            raise Exception(f'invalid button: {self._button}')
  79
  80        brightness = 4.0
  81        if color is not None:
  82            c_bright = list(color)
  83            c_bright[0] *= brightness
  84            c_bright[1] *= brightness
  85            c_bright[2] *= brightness
  86        else:
  87            c_bright = [1.0, 1.0, 1.0]
  88
  89        if self._delay == 0:
  90            call()
  91            if img is not None:
  92                img.color = c_bright
  93                img.vr_depth = -40
  94        else:
  95            ba.timer(self._delay, call, timeformat=ba.TimeFormat.MILLISECONDS)
  96            if img is not None:
  97                ba.timer(self._delay,
  98                         ba.Call(_safesetattr, img, 'color', c_bright),
  99                         timeformat=ba.TimeFormat.MILLISECONDS)
 100                ba.timer(self._delay,
 101                         ba.Call(_safesetattr, img, 'vr_depth', -30),
 102                         timeformat=ba.TimeFormat.MILLISECONDS)
 103        if self._release:
 104            if self._delay == 0 and self._release_delay == 0:
 105                release_call()
 106            else:
 107                ba.timer(0.001 * (self._delay + self._release_delay),
 108                         release_call)
 109            if img is not None:
 110                ba.timer(self._delay + self._release_delay + 100,
 111                         ba.Call(_safesetattr, img, 'color', color),
 112                         timeformat=ba.TimeFormat.MILLISECONDS)
 113                ba.timer(self._delay + self._release_delay + 100,
 114                         ba.Call(_safesetattr, img, 'vr_depth', -20),
 115                         timeformat=ba.TimeFormat.MILLISECONDS)
 116
 117
 118class ButtonRelease:
 119
 120    def __init__(self, button: str, delay: int = 0):
 121        self._button = button
 122        self._delay = delay
 123
 124    def run(self, a: TutorialActivity) -> None:
 125        s = a.current_spaz
 126        assert s is not None
 127        call: Callable[[], None] | None
 128        img: ba.Node | None
 129        color: Sequence[float] | None
 130        if self._button == 'punch':
 131            call = s.on_punch_release
 132            img = a.punch_image
 133            color = a.punch_image_color
 134        elif self._button == 'jump':
 135            call = s.on_jump_release
 136            img = a.jump_image
 137            color = a.jump_image_color
 138        elif self._button == 'bomb':
 139            call = s.on_bomb_release
 140            img = a.bomb_image
 141            color = a.bomb_image_color
 142        elif self._button == 'pickUp':
 143            call = s.on_pickup_press
 144            img = a.pickup_image
 145            color = a.pickup_image_color
 146        elif self._button == 'run':
 147            call = ba.Call(s.on_run, 0.0)
 148            img = None
 149            color = None
 150        else:
 151            raise Exception('invalid button: ' + self._button)
 152        if self._delay == 0:
 153            call()
 154        else:
 155            ba.timer(self._delay, call, timeformat=ba.TimeFormat.MILLISECONDS)
 156        if img is not None:
 157            ba.timer(self._delay + 100,
 158                     ba.Call(_safesetattr, img, 'color', color),
 159                     timeformat=ba.TimeFormat.MILLISECONDS)
 160            ba.timer(self._delay + 100,
 161                     ba.Call(_safesetattr, img, 'vr_depth', -20),
 162                     timeformat=ba.TimeFormat.MILLISECONDS)
 163
 164
 165class Player(ba.Player['Team']):
 166    """Our player type for this game."""
 167
 168    def __init__(self) -> None:
 169        self.pressed = False
 170
 171
 172class Team(ba.Team[Player]):
 173    """Our team type for this game."""
 174
 175    def __init__(self) -> None:
 176        pass
 177
 178
 179class TutorialActivity(ba.Activity[Player, Team]):
 180
 181    def __init__(self, settings: dict | None = None):
 182        from bastd.maps import Rampage
 183        if settings is None:
 184            settings = {}
 185        super().__init__(settings)
 186        self.current_spaz: basespaz.Spaz | None = None
 187        self._benchmark_type = getattr(ba.getsession(), 'benchmark_type', None)
 188        self.last_start_time: int | None = None
 189        self.cycle_times: list[int] = []
 190        self.allow_pausing = True
 191        self.allow_kick_idle_players = False
 192        self._issued_warning = False
 193        self._map_type = Rampage
 194        self._map_type.preload()
 195        self._jump_button_tex = ba.gettexture('buttonJump')
 196        self._pick_up_button_tex = ba.gettexture('buttonPickUp')
 197        self._bomb_button_tex = ba.gettexture('buttonBomb')
 198        self._punch_button_tex = ba.gettexture('buttonPunch')
 199        self._r = 'tutorial'
 200        self._have_skipped = False
 201        self.stick_image_position_x = self.stick_image_position_y = 0.0
 202        self.spawn_sound = ba.getsound('spawn')
 203        self.map: ba.Map | None = None
 204        self.text: ba.Node | None = None
 205        self._skip_text: ba.Node | None = None
 206        self._skip_count_text: ba.Node | None = None
 207        self._scale: float | None = None
 208        self._stick_base_position: tuple[float, float] = (0.0, 0.0)
 209        self._stick_nub_position: tuple[float, float] = (0.0, 0.0)
 210        self._stick_base_image_color: Sequence[float] = (1.0, 1.0, 1.0, 1.0)
 211        self._stick_nub_image_color: Sequence[float] = (1.0, 1.0, 1.0, 1.0)
 212        self._time: int = -1
 213        self.punch_image_color = (1.0, 1.0, 1.0)
 214        self.punch_image: ba.Node | None = None
 215        self.bomb_image: ba.Node | None = None
 216        self.jump_image: ba.Node | None = None
 217        self.pickup_image: ba.Node | None = None
 218        self._stick_base_image: ba.Node | None = None
 219        self._stick_nub_image: ba.Node | None = None
 220        self.bomb_image_color = (1.0, 1.0, 1.0)
 221        self.pickup_image_color = (1.0, 1.0, 1.0)
 222        self.control_ui_nodes: list[ba.Node] = []
 223        self.spazzes: dict[int, basespaz.Spaz] = {}
 224        self.jump_image_color = (1.0, 1.0, 1.0)
 225        self._entries: list[Any] = []
 226        self._read_entries_timer: ba.Timer | None = None
 227        self._entry_timer: ba.Timer | None = None
 228
 229    def on_transition_in(self) -> None:
 230        super().on_transition_in()
 231        ba.setmusic(ba.MusicType.CHAR_SELECT, continuous=True)
 232        self.map = self._map_type()
 233
 234    def on_begin(self) -> None:
 235        super().on_begin()
 236
 237        ba.set_analytics_screen('Tutorial Start')
 238        _ba.increment_analytics_count('Tutorial start')
 239
 240        if bool(False):
 241            # Buttons on top.
 242            text_y = 140
 243            buttons_y = 250
 244        else:
 245            # Buttons on bottom.
 246            text_y = 260
 247            buttons_y = 160
 248
 249        # Need different versions of this: taps/buttons/keys.
 250        self.text = ba.newnode('text',
 251                               attrs={
 252                                   'text': '',
 253                                   'scale': 1.9,
 254                                   'position': (0, text_y),
 255                                   'maxwidth': 500,
 256                                   'flatness': 0.0,
 257                                   'shadow': 0.5,
 258                                   'h_align': 'center',
 259                                   'v_align': 'center',
 260                                   'v_attach': 'center'
 261                               })
 262
 263        # Need different versions of this: taps/buttons/keys.
 264        txt = ba.Lstr(
 265            resource=self._r +
 266            '.cpuBenchmarkText') if self._benchmark_type == 'cpu' else ba.Lstr(
 267                resource=self._r + '.toSkipPressAnythingText')
 268        t = self._skip_text = ba.newnode('text',
 269                                         attrs={
 270                                             'text': txt,
 271                                             'maxwidth': 900,
 272                                             'scale': 1.1,
 273                                             'vr_depth': 100,
 274                                             'position': (0, 30),
 275                                             'h_align': 'center',
 276                                             'v_align': 'center',
 277                                             'v_attach': 'bottom'
 278                                         })
 279        ba.animate(t, 'opacity', {1.0: 0.0, 2.0: 0.7})
 280        self._skip_count_text = ba.newnode('text',
 281                                           attrs={
 282                                               'text': '',
 283                                               'scale': 1.4,
 284                                               'vr_depth': 90,
 285                                               'position': (0, 70),
 286                                               'h_align': 'center',
 287                                               'v_align': 'center',
 288                                               'v_attach': 'bottom'
 289                                           })
 290
 291        ouya = False
 292
 293        self._scale = scale = 0.6
 294        center_offs = 130.0 * scale
 295        offs = 65.0 * scale
 296        position = (0, buttons_y)
 297        image_size = 90.0 * scale
 298        image_size_2 = 220.0 * scale
 299        nub_size = 110.0 * scale
 300        p = (position[0] + center_offs, position[1] - offs)
 301
 302        def _sc(r: float, g: float, b: float) -> tuple[float, float, float]:
 303            return 0.6 * r, 0.6 * g, 0.6 * b
 304
 305        self.jump_image_color = c = _sc(0.4, 1, 0.4)
 306        self.jump_image = ba.newnode('image',
 307                                     attrs={
 308                                         'texture': self._jump_button_tex,
 309                                         'absolute_scale': True,
 310                                         'vr_depth': -20,
 311                                         'position': p,
 312                                         'scale': (image_size, image_size),
 313                                         'color': c
 314                                     })
 315        p = (position[0] + center_offs - offs, position[1])
 316        self.punch_image_color = c = _sc(0.2, 0.6, 1) if ouya else _sc(
 317            1, 0.7, 0.3)
 318        self.punch_image = ba.newnode(
 319            'image',
 320            attrs={
 321                'texture': ba.gettexture('buttonPunch'),
 322                'absolute_scale': True,
 323                'vr_depth': -20,
 324                'position': p,
 325                'scale': (image_size, image_size),
 326                'color': c
 327            })
 328        p = (position[0] + center_offs + offs, position[1])
 329        self.bomb_image_color = c = _sc(1, 0.3, 0.3)
 330        self.bomb_image = ba.newnode(
 331            'image',
 332            attrs={
 333                'texture': ba.gettexture('buttonBomb'),
 334                'absolute_scale': True,
 335                'vr_depth': -20,
 336                'position': p,
 337                'scale': (image_size, image_size),
 338                'color': c
 339            })
 340        p = (position[0] + center_offs, position[1] + offs)
 341        self.pickup_image_color = c = _sc(1, 0.8, 0.3) if ouya else _sc(
 342            0.5, 0.5, 1)
 343        self.pickup_image = ba.newnode(
 344            'image',
 345            attrs={
 346                'texture': ba.gettexture('buttonPickUp'),
 347                'absolute_scale': True,
 348                'vr_depth': -20,
 349                'position': p,
 350                'scale': (image_size, image_size),
 351                'color': c
 352            })
 353
 354        self._stick_base_position = p = (position[0] - center_offs,
 355                                         position[1])
 356        self._stick_base_image_color = c2 = (0.25, 0.25, 0.25, 1.0)
 357        self._stick_base_image = ba.newnode(
 358            'image',
 359            attrs={
 360                'texture': ba.gettexture('nub'),
 361                'absolute_scale': True,
 362                'vr_depth': -40,
 363                'position': p,
 364                'scale': (image_size_2, image_size_2),
 365                'color': c2
 366            })
 367        self._stick_nub_position = p = (position[0] - center_offs, position[1])
 368        self._stick_nub_image_color = c3 = (0.4, 0.4, 0.4, 1.0)
 369        self._stick_nub_image = ba.newnode('image',
 370                                           attrs={
 371                                               'texture': ba.gettexture('nub'),
 372                                               'absolute_scale': True,
 373                                               'position': p,
 374                                               'scale': (nub_size, nub_size),
 375                                               'color': c3
 376                                           })
 377        self.control_ui_nodes = [
 378            self.jump_image, self.punch_image, self.bomb_image,
 379            self.pickup_image, self._stick_base_image, self._stick_nub_image
 380        ]
 381        for n in self.control_ui_nodes:
 382            n.opacity = 0.0
 383        self._read_entries()
 384
 385    def set_stick_image_position(self, x: float, y: float) -> None:
 386
 387        # Clamp this to a circle.
 388        len_squared = x * x + y * y
 389        if len_squared > 1.0:
 390            length = math.sqrt(len_squared)
 391            mult = 1.0 / length
 392            x *= mult
 393            y *= mult
 394
 395        self.stick_image_position_x = x
 396        self.stick_image_position_y = y
 397        offs = 50.0
 398        assert self._scale is not None
 399        p = [
 400            self._stick_nub_position[0] + x * offs * self._scale,
 401            self._stick_nub_position[1] + y * offs * self._scale
 402        ]
 403        c = list(self._stick_nub_image_color)
 404        if abs(x) > 0.1 or abs(y) > 0.1:
 405            c[0] *= 2.0
 406            c[1] *= 4.0
 407            c[2] *= 2.0
 408        assert self._stick_nub_image is not None
 409        self._stick_nub_image.position = p
 410        self._stick_nub_image.color = c
 411        c = list(self._stick_base_image_color)
 412        if abs(x) > 0.1 or abs(y) > 0.1:
 413            c[0] *= 1.5
 414            c[1] *= 1.5
 415            c[2] *= 1.5
 416        assert self._stick_base_image is not None
 417        self._stick_base_image.color = c
 418
 419    def _read_entries(self) -> None:
 420        try:
 421
 422            class Reset:
 423
 424                def __init__(self) -> None:
 425                    pass
 426
 427                def run(self, a: TutorialActivity) -> None:
 428
 429                    # if we're looping, print out how long each cycle took
 430                    # print out how long each cycle took..
 431                    if a.last_start_time is not None:
 432                        tval = ba.time(
 433                            ba.TimeType.REAL,
 434                            ba.TimeFormat.MILLISECONDS) - a.last_start_time
 435                        assert isinstance(tval, int)
 436                        diff = tval
 437                        a.cycle_times.append(diff)
 438                        ba.screenmessage(
 439                            'cycle time: ' + str(diff) + ' (average: ' +
 440                            str(sum(a.cycle_times) / len(a.cycle_times)) + ')')
 441                    tval = ba.time(ba.TimeType.REAL,
 442                                   ba.TimeFormat.MILLISECONDS)
 443                    assert isinstance(tval, int)
 444                    a.last_start_time = tval
 445
 446                    assert a.text
 447                    a.text.text = ''
 448                    for spaz in list(a.spazzes.values()):
 449                        spaz.handlemessage(ba.DieMessage(immediate=True))
 450                    a.spazzes = {}
 451                    a.current_spaz = None
 452                    for n in a.control_ui_nodes:
 453                        n.opacity = 0.0
 454                    a.set_stick_image_position(0, 0)
 455
 456            # Can be used for debugging.
 457            class SetSpeed:
 458
 459                def __init__(self, speed: int):
 460                    self._speed = speed
 461
 462                def run(self, a: TutorialActivity) -> None:
 463                    print('setting to', self._speed)
 464                    _ba.set_debug_speed_exponent(self._speed)
 465
 466            class RemoveGloves:
 467
 468                def __init__(self) -> None:
 469                    pass
 470
 471                def run(self, a: TutorialActivity) -> None:
 472                    # pylint: disable=protected-access
 473                    assert a.current_spaz is not None
 474                    # noinspection PyProtectedMember
 475                    a.current_spaz._gloves_wear_off()
 476
 477            class KillSpaz:
 478
 479                def __init__(self, num: int, explode: bool = False):
 480                    self._num = num
 481                    self._explode = explode
 482
 483                def run(self, a: TutorialActivity) -> None:
 484                    if self._explode:
 485                        a.spazzes[self._num].shatter()
 486                    del a.spazzes[self._num]
 487
 488            class SpawnSpaz:
 489
 490                def __init__(self,
 491                             num: int,
 492                             position: Sequence[float],
 493                             color: Sequence[float] = (1.0, 1.0, 1.0),
 494                             make_current: bool = False,
 495                             relative_to: int | None = None,
 496                             name: str | ba.Lstr = '',
 497                             flash: bool = True,
 498                             angle: float = 0.0):
 499                    self._num = num
 500                    self._position = position
 501                    self._make_current = make_current
 502                    self._color = color
 503                    self._relative_to = relative_to
 504                    self._name = name
 505                    self._flash = flash
 506                    self._angle = angle
 507
 508                def run(self, a: TutorialActivity) -> None:
 509
 510                    # if they gave a 'relative to' spaz, position is relative
 511                    # to them
 512                    pos: Sequence[float]
 513                    if self._relative_to is not None:
 514                        snode = a.spazzes[self._relative_to].node
 515                        assert snode
 516                        their_pos = snode.position
 517                        pos = (their_pos[0] + self._position[0],
 518                               their_pos[1] + self._position[1],
 519                               their_pos[2] + self._position[2])
 520                    else:
 521                        pos = self._position
 522
 523                    # if there's already a spaz at this spot, insta-kill it
 524                    if self._num in a.spazzes:
 525                        a.spazzes[self._num].handlemessage(
 526                            ba.DieMessage(immediate=True))
 527
 528                    s = a.spazzes[self._num] = basespaz.Spaz(
 529                        color=self._color,
 530                        start_invincible=self._flash,
 531                        demo_mode=True)
 532
 533                    # FIXME: Should extend spaz to support Lstr names.
 534                    assert s.node
 535                    if isinstance(self._name, ba.Lstr):
 536                        s.node.name = self._name.evaluate()
 537                    else:
 538                        s.node.name = self._name
 539                    s.node.name_color = self._color
 540                    s.handlemessage(ba.StandMessage(pos, self._angle))
 541                    if self._make_current:
 542                        a.current_spaz = s
 543                    if self._flash:
 544                        ba.playsound(a.spawn_sound, position=pos)
 545
 546            class Powerup:
 547
 548                def __init__(self,
 549                             num: int,
 550                             position: Sequence[float],
 551                             color: Sequence[float] = (1.0, 1.0, 1.0),
 552                             make_current: bool = False,
 553                             relative_to: int | None = None):
 554                    self._position = position
 555                    self._relative_to = relative_to
 556
 557                def run(self, a: TutorialActivity) -> None:
 558                    # If they gave a 'relative to' spaz, position is relative
 559                    # to them.
 560                    pos: Sequence[float]
 561                    if self._relative_to is not None:
 562                        snode = a.spazzes[self._relative_to].node
 563                        assert snode
 564                        their_pos = snode.position
 565                        pos = (their_pos[0] + self._position[0],
 566                               their_pos[1] + self._position[1],
 567                               their_pos[2] + self._position[2])
 568                    else:
 569                        pos = self._position
 570                    from bastd.actor import powerupbox
 571                    powerupbox.PowerupBox(position=pos,
 572                                          poweruptype='punch').autoretain()
 573
 574            class Delay:
 575
 576                def __init__(self, time: int) -> None:
 577                    self._time = time
 578
 579                def run(self, a: TutorialActivity) -> int:
 580                    return self._time
 581
 582            class AnalyticsScreen:
 583
 584                def __init__(self, screen: str) -> None:
 585                    self._screen = screen
 586
 587                def run(self, a: TutorialActivity) -> None:
 588                    ba.set_analytics_screen(self._screen)
 589
 590            class DelayOld:
 591
 592                def __init__(self, time: int) -> None:
 593                    self._time = time
 594
 595                def run(self, a: TutorialActivity) -> int:
 596                    return int(0.9 * self._time)
 597
 598            class DelayOld2:
 599
 600                def __init__(self, time: int) -> None:
 601                    self._time = time
 602
 603                def run(self, a: TutorialActivity) -> int:
 604                    return int(0.8 * self._time)
 605
 606            class End:
 607
 608                def __init__(self) -> None:
 609                    pass
 610
 611                def run(self, a: TutorialActivity) -> None:
 612                    _ba.increment_analytics_count('Tutorial finish')
 613                    a.end()
 614
 615            class Move:
 616
 617                def __init__(self, x: float, y: float):
 618                    self._x = float(x)
 619                    self._y = float(y)
 620
 621                def run(self, a: TutorialActivity) -> None:
 622                    s = a.current_spaz
 623                    assert s
 624                    # FIXME: Game should take floats for this.
 625                    x_clamped = self._x
 626                    y_clamped = self._y
 627                    s.on_move_left_right(x_clamped)
 628                    s.on_move_up_down(y_clamped)
 629                    a.set_stick_image_position(self._x, self._y)
 630
 631            class MoveLR:
 632
 633                def __init__(self, x: float):
 634                    self._x = float(x)
 635
 636                def run(self, a: TutorialActivity) -> None:
 637                    s = a.current_spaz
 638                    assert s
 639                    # FIXME: Game should take floats for this.
 640                    x_clamped = self._x
 641                    s.on_move_left_right(x_clamped)
 642                    a.set_stick_image_position(self._x,
 643                                               a.stick_image_position_y)
 644
 645            class MoveUD:
 646
 647                def __init__(self, y: float):
 648                    self._y = float(y)
 649
 650                def run(self, a: TutorialActivity) -> None:
 651                    s = a.current_spaz
 652                    assert s
 653                    # FIXME: Game should take floats for this.
 654                    y_clamped = self._y
 655                    s.on_move_up_down(y_clamped)
 656                    a.set_stick_image_position(a.stick_image_position_x,
 657                                               self._y)
 658
 659            class Bomb(ButtonPress):
 660
 661                def __init__(self,
 662                             delay: int = 0,
 663                             release: bool = True,
 664                             release_delay: int = 500):
 665                    ButtonPress.__init__(self,
 666                                         'bomb',
 667                                         delay=delay,
 668                                         release=release,
 669                                         release_delay=release_delay)
 670
 671            class Jump(ButtonPress):
 672
 673                def __init__(self,
 674                             delay: int = 0,
 675                             release: bool = True,
 676                             release_delay: int = 500):
 677                    ButtonPress.__init__(self,
 678                                         'jump',
 679                                         delay=delay,
 680                                         release=release,
 681                                         release_delay=release_delay)
 682
 683            class Punch(ButtonPress):
 684
 685                def __init__(self,
 686                             delay: int = 0,
 687                             release: bool = True,
 688                             release_delay: int = 500):
 689                    ButtonPress.__init__(self,
 690                                         'punch',
 691                                         delay=delay,
 692                                         release=release,
 693                                         release_delay=release_delay)
 694
 695            class PickUp(ButtonPress):
 696
 697                def __init__(self,
 698                             delay: int = 0,
 699                             release: bool = True,
 700                             release_delay: int = 500):
 701                    ButtonPress.__init__(self,
 702                                         'pickUp',
 703                                         delay=delay,
 704                                         release=release,
 705                                         release_delay=release_delay)
 706
 707            class Run(ButtonPress):
 708
 709                def __init__(self,
 710                             delay: int = 0,
 711                             release: bool = True,
 712                             release_delay: int = 500):
 713                    ButtonPress.__init__(self,
 714                                         'run',
 715                                         delay=delay,
 716                                         release=release,
 717                                         release_delay=release_delay)
 718
 719            class BombRelease(ButtonRelease):
 720
 721                def __init__(self, delay: int = 0):
 722                    super().__init__('bomb', delay=delay)
 723
 724            class JumpRelease(ButtonRelease):
 725
 726                def __init__(self, delay: int = 0):
 727                    super().__init__('jump', delay=delay)
 728
 729            class PunchRelease(ButtonRelease):
 730
 731                def __init__(self, delay: int = 0):
 732                    super().__init__('punch', delay=delay)
 733
 734            class PickUpRelease(ButtonRelease):
 735
 736                def __init__(self, delay: int = 0):
 737                    super().__init__('pickUp', delay=delay)
 738
 739            class RunRelease(ButtonRelease):
 740
 741                def __init__(self, delay: int = 0):
 742                    super().__init__('run', delay=delay)
 743
 744            class ShowControls:
 745
 746                def __init__(self) -> None:
 747                    pass
 748
 749                def run(self, a: TutorialActivity) -> None:
 750                    for n in a.control_ui_nodes:
 751                        ba.animate(n, 'opacity', {0.0: 0.0, 1.0: 1.0})
 752
 753            class Text:
 754
 755                def __init__(self, text: str | ba.Lstr):
 756                    self.text = text
 757
 758                def run(self, a: TutorialActivity) -> None:
 759                    assert a.text
 760                    a.text.text = self.text
 761
 762            class PrintPos:
 763
 764                def __init__(self, spaz_num: int | None = None):
 765                    self._spaz_num = spaz_num
 766
 767                def run(self, a: TutorialActivity) -> None:
 768                    if self._spaz_num is None:
 769                        s = a.current_spaz
 770                    else:
 771                        s = a.spazzes[self._spaz_num]
 772                    assert s and s.node
 773                    t = list(s.node.position)
 774                    print('RestorePos(' + str((t[0], t[1] - 1.0, t[2])) + '),')
 775
 776            class RestorePos:
 777
 778                def __init__(self, pos: Sequence[float]) -> None:
 779                    self._pos = pos
 780
 781                def run(self, a: TutorialActivity) -> None:
 782                    s = a.current_spaz
 783                    assert s
 784                    s.handlemessage(ba.StandMessage(self._pos, 0))
 785
 786            class Celebrate:
 787
 788                def __init__(self,
 789                             celebrate_type: str = 'both',
 790                             spaz_num: int | None = None,
 791                             duration: int = 1000):
 792                    self._spaz_num = spaz_num
 793                    self._celebrate_type = celebrate_type
 794                    self._duration = duration
 795
 796                def run(self, a: TutorialActivity) -> None:
 797                    if self._spaz_num is None:
 798                        s = a.current_spaz
 799                    else:
 800                        s = a.spazzes[self._spaz_num]
 801                    assert s and s.node
 802                    if self._celebrate_type == 'right':
 803                        s.node.handlemessage('celebrate_r', self._duration)
 804                    elif self._celebrate_type == 'left':
 805                        s.node.handlemessage('celebrate_l', self._duration)
 806                    elif self._celebrate_type == 'both':
 807                        s.node.handlemessage('celebrate', self._duration)
 808                    else:
 809                        raise Exception('invalid celebrate type ' +
 810                                        self._celebrate_type)
 811
 812            self._entries = [
 813                Reset(),
 814                SpawnSpaz(0, (0, 5.5, -3.0), make_current=True),
 815                DelayOld(1000),
 816                AnalyticsScreen('Tutorial Section 1'),
 817                Text(ba.Lstr(resource=self._r + '.phrase01Text')),  # hi there
 818                Celebrate('left'),
 819                DelayOld(2000),
 820                Text(
 821                    ba.Lstr(resource=self._r + '.phrase02Text',
 822                            subs=[
 823                                ('${APP_NAME}', ba.Lstr(resource='titleText'))
 824                            ])),  # welcome to <appname>
 825                DelayOld(80),
 826                Run(release=False),
 827                Jump(release=False),
 828                MoveLR(1),
 829                MoveUD(0),
 830                DelayOld(70),
 831                RunRelease(),
 832                JumpRelease(),
 833                DelayOld(60),
 834                MoveUD(1),
 835                DelayOld(30),
 836                MoveLR(0),
 837                DelayOld(90),
 838                MoveLR(-1),
 839                DelayOld(20),
 840                MoveUD(0),
 841                DelayOld(70),
 842                MoveUD(-1),
 843                DelayOld(20),
 844                MoveLR(0),
 845                DelayOld(80),
 846                MoveUD(0),
 847                DelayOld(1500),
 848                Text(ba.Lstr(resource=self._r +
 849                             '.phrase03Text')),  # here's a few tips
 850                DelayOld(1000),
 851                ShowControls(),
 852                DelayOld(1000),
 853                Jump(),
 854                DelayOld(1000),
 855                Jump(),
 856                DelayOld(1000),
 857                AnalyticsScreen('Tutorial Section 2'),
 858                Text(
 859                    ba.Lstr(resource=self._r + '.phrase04Text',
 860                            subs=[
 861                                ('${APP_NAME}', ba.Lstr(resource='titleText'))
 862                            ])),  # many things are based on physics
 863                DelayOld(20),
 864                MoveUD(0),
 865                DelayOld(60),
 866                MoveLR(0),
 867                DelayOld(10),
 868                MoveLR(0),
 869                MoveUD(0),
 870                DelayOld(10),
 871                MoveLR(0),
 872                MoveUD(0),
 873                DelayOld(20),
 874                MoveUD(-0.0575579),
 875                DelayOld(10),
 876                MoveUD(-0.207831),
 877                DelayOld(30),
 878                MoveUD(-0.309793),
 879                DelayOld(10),
 880                MoveUD(-0.474502),
 881                DelayOld(10),
 882                MoveLR(0.00390637),
 883                MoveUD(-0.647053),
 884                DelayOld(20),
 885                MoveLR(-0.0745262),
 886                MoveUD(-0.819605),
 887                DelayOld(10),
 888                MoveLR(-0.168645),
 889                MoveUD(-0.937254),
 890                DelayOld(30),
 891                MoveLR(-0.294137),
 892                MoveUD(-1),
 893                DelayOld(10),
 894                MoveLR(-0.411786),
 895                DelayOld(10),
 896                MoveLR(-0.639241),
 897                DelayOld(30),
 898                MoveLR(-0.75689),
 899                DelayOld(10),
 900                MoveLR(-0.905911),
 901                DelayOld(20),
 902                MoveLR(-1),
 903                DelayOld(50),
 904                MoveUD(-0.960784),
 905                DelayOld(20),
 906                MoveUD(-0.819605),
 907                MoveUD(-0.61568),
 908                DelayOld(20),
 909                MoveUD(-0.427442),
 910                DelayOld(20),
 911                MoveUD(-0.231361),
 912                DelayOld(10),
 913                MoveUD(-0.00390637),
 914                DelayOld(30),
 915                MoveUD(0.333354),
 916                MoveUD(0.584338),
 917                DelayOld(20),
 918                MoveUD(0.764733),
 919                DelayOld(30),
 920                MoveLR(-0.803949),
 921                MoveUD(0.913755),
 922                DelayOld(10),
 923                MoveLR(-0.647084),
 924                MoveUD(0.992187),
 925                DelayOld(20),
 926                MoveLR(-0.435316),
 927                MoveUD(1),
 928                DelayOld(20),
 929                MoveLR(-0.168645),
 930                MoveUD(0.976501),
 931                MoveLR(0.0744957),
 932                MoveUD(0.905911),
 933                DelayOld(20),
 934                MoveLR(0.270577),
 935                MoveUD(0.843165),
 936                DelayOld(20),
 937                MoveLR(0.435286),
 938                MoveUD(0.780419),
 939                DelayOld(10),
 940                MoveLR(0.66274),
 941                MoveUD(0.647084),
 942                DelayOld(30),
 943                MoveLR(0.803919),
 944                MoveUD(0.458846),
 945                MoveLR(0.929411),
 946                MoveUD(0.223548),
 947                DelayOld(20),
 948                MoveLR(0.95294),
 949                MoveUD(0.137272),
 950                DelayOld(20),
 951                MoveLR(1),
 952                MoveUD(-0.0509659),
 953                DelayOld(20),
 954                MoveUD(-0.247047),
 955                DelayOld(20),
 956                MoveUD(-0.443129),
 957                DelayOld(20),
 958                MoveUD(-0.694113),
 959                MoveUD(-0.921567),
 960                DelayOld(30),
 961                MoveLR(0.858821),
 962                MoveUD(-1),
 963                DelayOld(10),
 964                MoveLR(0.68627),
 965                DelayOld(10),
 966                MoveLR(0.364696),
 967                DelayOld(20),
 968                MoveLR(0.0509659),
 969                DelayOld(20),
 970                MoveLR(-0.223548),
 971                DelayOld(10),
 972                MoveLR(-0.600024),
 973                MoveUD(-0.913724),
 974                DelayOld(30),
 975                MoveLR(-0.858852),
 976                MoveUD(-0.717643),
 977                MoveLR(-1),
 978                MoveUD(-0.474502),
 979                DelayOld(20),
 980                MoveUD(-0.396069),
 981                DelayOld(20),
 982                MoveUD(-0.286264),
 983                DelayOld(20),
 984                MoveUD(-0.137242),
 985                DelayOld(20),
 986                MoveUD(0.0353099),
 987                DelayOld(10),
 988                MoveUD(0.32551),
 989                DelayOld(20),
 990                MoveUD(0.592181),
 991                DelayOld(10),
 992                MoveUD(0.851009),
 993                DelayOld(10),
 994                MoveUD(1),
 995                DelayOld(30),
 996                MoveLR(-0.764733),
 997                DelayOld(20),
 998                MoveLR(-0.403943),
 999                MoveLR(-0.145116),
1000                DelayOld(30),
1001                MoveLR(0.0901822),
1002                MoveLR(0.32548),
1003                DelayOld(30),
1004                MoveLR(0.560778),
1005                MoveUD(0.929441),
1006                DelayOld(20),
1007                MoveLR(0.709799),
1008                MoveUD(0.73336),
1009                MoveLR(0.803919),
1010                MoveUD(0.545122),
1011                DelayOld(20),
1012                MoveLR(0.882351),
1013                MoveUD(0.356883),
1014                DelayOld(10),
1015                MoveLR(0.968627),
1016                MoveUD(0.113742),
1017                DelayOld(20),
1018                MoveLR(0.992157),
1019                MoveUD(-0.0823389),
1020                DelayOld(30),
1021                MoveUD(-0.309793),
1022                DelayOld(10),
1023                MoveUD(-0.545091),
1024                DelayOld(20),
1025                MoveLR(0.882351),
1026                MoveUD(-0.874508),
1027                DelayOld(20),
1028                MoveLR(0.756859),
1029                MoveUD(-1),
1030                DelayOld(10),
1031                MoveLR(0.576464),
1032                DelayOld(20),
1033                MoveLR(0.254891),
1034                DelayOld(10),
1035                MoveLR(-0.0274667),
1036                DelayOld(10),
1037                MoveLR(-0.356883),
1038                DelayOld(30),
1039                MoveLR(-0.592181),
1040                MoveLR(-0.827479),
1041                MoveUD(-0.921567),
1042                DelayOld(20),
1043                MoveLR(-1),
1044                MoveUD(-0.749016),
1045                DelayOld(20),
1046                MoveUD(-0.61568),
1047                DelayOld(10),
1048                MoveUD(-0.403912),
1049                DelayOld(20),
1050                MoveUD(-0.207831),
1051                DelayOld(10),
1052                MoveUD(0.121586),
1053                DelayOld(30),
1054                MoveUD(0.34904),
1055                DelayOld(10),
1056                MoveUD(0.560808),
1057                DelayOld(10),
1058                MoveUD(0.827479),
1059                DelayOld(30),
1060                MoveUD(1),
1061                DelayOld(20),
1062                MoveLR(-0.976501),
1063                MoveLR(-0.670614),
1064                DelayOld(20),
1065                MoveLR(-0.239235),
1066                DelayOld(20),
1067                MoveLR(0.160772),
1068                DelayOld(20),
1069                MoveLR(0.443129),
1070                DelayOld(10),
1071                MoveLR(0.68627),
1072                MoveUD(0.976501),
1073                DelayOld(30),
1074                MoveLR(0.929411),
1075                MoveUD(0.73336),
1076                MoveLR(1),
1077                MoveUD(0.482376),
1078                DelayOld(20),
1079                MoveUD(0.34904),
1080                DelayOld(10),
1081                MoveUD(0.160802),
1082                DelayOld(30),
1083                MoveUD(-0.0744957),
1084                DelayOld(10),
1085                MoveUD(-0.333323),
1086                DelayOld(20),
1087                MoveUD(-0.647053),
1088                DelayOld(20),
1089                MoveUD(-0.937254),
1090                DelayOld(10),
1091                MoveLR(0.858821),
1092                MoveUD(-1),
1093                DelayOld(10),
1094                MoveLR(0.576464),
1095                DelayOld(30),
1096                MoveLR(0.184301),
1097                DelayOld(10),
1098                MoveLR(-0.121586),
1099                DelayOld(10),
1100                MoveLR(-0.474532),
1101                DelayOld(30),
1102                MoveLR(-0.670614),
1103                MoveLR(-0.851009),
1104                DelayOld(30),
1105                MoveLR(-1),
1106                MoveUD(-0.968627),
1107                DelayOld(20),
1108                MoveUD(-0.843135),
1109                DelayOld(10),
1110                MoveUD(-0.631367),
1111                DelayOld(20),
1112                MoveUD(-0.403912),
1113                MoveUD(-0.176458),
1114                DelayOld(20),
1115                MoveUD(0.0902127),
1116                DelayOld(20),
1117                MoveUD(0.380413),
1118                DelayOld(10),
1119                MoveUD(0.717673),
1120                DelayOld(30),
1121                MoveUD(1),
1122                DelayOld(10),
1123                MoveLR(-0.741203),
1124                DelayOld(20),
1125                MoveLR(-0.458846),
1126                DelayOld(10),
1127                MoveLR(-0.145116),
1128                DelayOld(10),
1129                MoveLR(0.0980255),
1130                DelayOld(20),
1131                MoveLR(0.294107),
1132                DelayOld(30),
1133                MoveLR(0.466659),
1134                MoveLR(0.717643),
1135                MoveUD(0.796106),
1136                DelayOld(20),
1137                MoveLR(0.921567),
1138                MoveUD(0.443159),
1139                DelayOld(20),
1140                MoveLR(1),
1141                MoveUD(0.145116),
1142                DelayOld(10),
1143                MoveUD(-0.0274361),
1144                DelayOld(30),
1145                MoveUD(-0.223518),
1146                MoveUD(-0.427442),
1147                DelayOld(20),
1148                MoveUD(-0.874508),
1149                DelayOld(20),
1150                MoveUD(-1),
1151                DelayOld(10),
1152                MoveLR(0.929411),
1153                DelayOld(20),
1154                MoveLR(0.68627),
1155                DelayOld(20),
1156                MoveLR(0.364696),
1157                DelayOld(20),
1158                MoveLR(0.0431227),
1159                DelayOld(10),
1160                MoveLR(-0.333354),
1161                DelayOld(20),
1162                MoveLR(-0.639241),
1163                DelayOld(20),
1164                MoveLR(-0.968657),
1165                MoveUD(-0.968627),
1166                DelayOld(20),
1167                MoveLR(-1),
1168                MoveUD(-0.890194),
1169                MoveUD(-0.866665),
1170                DelayOld(20),
1171                MoveUD(-0.749016),
1172                DelayOld(20),
1173                MoveUD(-0.529405),
1174                DelayOld(20),
1175                MoveUD(-0.30195),
1176                DelayOld(10),
1177                MoveUD(-0.00390637),
1178                DelayOld(10),
1179                MoveUD(0.262764),
1180                DelayOld(30),
1181                MoveLR(-0.600024),
1182                MoveUD(0.458846),
1183                DelayOld(10),
1184                MoveLR(-0.294137),
1185                MoveUD(0.482376),
1186                DelayOld(20),
1187                MoveLR(-0.200018),
1188                MoveUD(0.505905),
1189                DelayOld(10),
1190                MoveLR(-0.145116),
1191                MoveUD(0.545122),
1192                DelayOld(20),
1193                MoveLR(-0.0353099),
1194                MoveUD(0.584338),
1195                DelayOld(20),
1196                MoveLR(0.137242),
1197                MoveUD(0.592181),
1198                DelayOld(20),
1199                MoveLR(0.30195),
1200                DelayOld(10),
1201                MoveLR(0.490188),
1202                DelayOld(10),
1203                MoveLR(0.599994),
1204                MoveUD(0.529435),
1205                DelayOld(30),
1206                MoveLR(0.66274),
1207                MoveUD(0.3961),
1208                DelayOld(20),
1209                MoveLR(0.670583),
1210                MoveUD(0.231391),
1211                MoveLR(0.68627),
1212                MoveUD(0.0745262),
1213                Move(0, -0.01),
1214                DelayOld(100),
1215                Move(0, 0),
1216                DelayOld(1000),
1217                Text(ba.Lstr(resource=self._r +
1218                             '.phrase05Text')),  # for example when you punch..
1219                DelayOld(510),
1220                Move(0, -0.01),
1221                DelayOld(100),
1222                Move(0, 0),
1223                DelayOld(500),
1224                SpawnSpaz(0, (-0.09249162673950195, 4.337906360626221, -2.3),
1225                          make_current=True,
1226                          flash=False),
1227                SpawnSpaz(1, (-3.1, 4.3, -2.0),
1228                          make_current=False,
1229                          color=(1, 1, 0.4),
1230                          name=ba.Lstr(resource=self._r + '.randomName1Text')),
1231                Move(-1.0, 0),
1232                DelayOld(1050),
1233                Move(0, -0.01),
1234                DelayOld(100),
1235                Move(0, 0),
1236                DelayOld(1000),
1237                Text(ba.Lstr(resource=self._r +
1238                             '.phrase06Text')),  # your damage is based
1239                DelayOld(1200),
1240                Move(-0.05, 0),
1241                DelayOld(200),
1242                Punch(),
1243                DelayOld(800),
1244                Punch(),
1245                DelayOld(800),
1246                Punch(),
1247                DelayOld(800),
1248                Move(0, -0.01),
1249                DelayOld(100),
1250                Move(0, 0),
1251                Text(
1252                    ba.Lstr(resource=self._r + '.phrase07Text',
1253                            subs=[('${NAME}',
1254                                   ba.Lstr(resource=self._r +
1255                                           '.randomName1Text'))
1256                                  ])),  # see that didn't hurt fred
1257                DelayOld(2000),
1258                Celebrate('right', spaz_num=1),
1259                DelayOld(1400),
1260                Text(ba.Lstr(
1261                    resource=self._r +
1262                    '.phrase08Text')),  # lets jump and spin to get more speed
1263                DelayOld(30),
1264                MoveLR(0),
1265                DelayOld(40),
1266                MoveLR(0),
1267                DelayOld(40),
1268                MoveLR(0),
1269                DelayOld(130),
1270                MoveLR(0),
1271                DelayOld(100),
1272                MoveLR(0),
1273                DelayOld(10),
1274                MoveLR(0.0480667),
1275                DelayOld(40),
1276                MoveLR(0.056093),
1277                MoveLR(0.0681173),
1278                DelayOld(30),
1279                MoveLR(0.0801416),
1280                DelayOld(10),
1281                MoveLR(0.184301),
1282                DelayOld(10),
1283                MoveLR(0.207831),
1284                DelayOld(20),
1285                MoveLR(0.231361),
1286                DelayOld(30),
1287                MoveLR(0.239204),
1288                DelayOld(30),
1289                MoveLR(0.254891),
1290                DelayOld(40),
1291                MoveLR(0.270577),
1292                DelayOld(10),
1293                MoveLR(0.30195),
1294                DelayOld(20),
1295                MoveLR(0.341166),
1296                DelayOld(30),
1297                MoveLR(0.388226),
1298                MoveLR(0.435286),
1299                DelayOld(30),
1300                MoveLR(0.490188),
1301                DelayOld(10),
1302                MoveLR(0.560778),
1303                DelayOld(20),
1304                MoveLR(0.599994),
1305                DelayOld(10),
1306                MoveLR(0.647053),
1307                DelayOld(10),
1308                MoveLR(0.68627),
1309                DelayOld(30),
1310                MoveLR(0.733329),
1311                DelayOld(20),
1312                MoveLR(0.764702),
1313                DelayOld(10),
1314                MoveLR(0.827448),
1315                DelayOld(20),
1316                MoveLR(0.874508),
1317                DelayOld(20),
1318                MoveLR(0.929411),
1319                DelayOld(10),
1320                MoveLR(1),
1321                DelayOld(830),
1322                MoveUD(0.0274667),
1323                DelayOld(10),
1324                MoveLR(0.95294),
1325                MoveUD(0.113742),
1326                DelayOld(30),
1327                MoveLR(0.780389),
1328                MoveUD(0.184332),
1329                DelayOld(10),
1330                MoveLR(0.27842),
1331                MoveUD(0.0745262),
1332                DelayOld(20),
1333                MoveLR(0),
1334                MoveUD(0),
1335                DelayOld(390),
1336                MoveLR(0),
1337                MoveLR(0),
1338                DelayOld(20),
1339                MoveLR(0),
1340                DelayOld(20),
1341                MoveLR(0),
1342                DelayOld(10),
1343                MoveLR(-0.0537431),
1344                DelayOld(20),
1345                MoveLR(-0.215705),
1346                DelayOld(30),
1347                MoveLR(-0.388256),
1348                MoveLR(-0.529435),
1349                DelayOld(30),
1350                MoveLR(-0.694143),
1351                DelayOld(20),
1352                MoveLR(-0.851009),
1353                MoveUD(0.0588397),
1354                DelayOld(10),
1355                MoveLR(-1),
1356                MoveUD(0.0745262),
1357                Run(release=False),
1358                DelayOld(200),
1359                MoveUD(0.0509964),
1360                DelayOld(30),
1361                MoveUD(0.0117801),
1362                DelayOld(20),
1363                MoveUD(-0.0901822),
1364                MoveUD(-0.372539),
1365                DelayOld(30),
1366                MoveLR(-0.898068),
1367                MoveUD(-0.890194),
1368                Jump(release=False),
1369                DelayOld(20),
1370                MoveLR(-0.647084),
1371                MoveUD(-1),
1372                MoveLR(-0.427473),
1373                DelayOld(20),
1374                MoveLR(-0.00393689),
1375                DelayOld(10),
1376                MoveLR(0.537248),
1377                DelayOld(30),
1378                MoveLR(1),
1379                DelayOld(50),
1380                RunRelease(),
1381                JumpRelease(),
1382                DelayOld(50),
1383                MoveUD(-0.921567),
1384                MoveUD(-0.749016),
1385                DelayOld(30),
1386                MoveUD(-0.552934),
1387                DelayOld(10),
1388                MoveUD(-0.247047),
1389                DelayOld(20),
1390                MoveUD(0.200018),
1391                DelayOld(20),
1392                MoveUD(0.670614),
1393                MoveUD(1),
1394                DelayOld(70),
1395                MoveLR(0.97647),
1396                DelayOld(20),
1397                MoveLR(0.764702),
1398                DelayOld(20),
1399                MoveLR(0.364696),
1400                DelayOld(20),
1401                MoveLR(0.00390637),
1402                MoveLR(-0.309824),
1403                DelayOld(20),
1404                MoveLR(-0.576495),
1405                DelayOld(30),
1406                MoveLR(-0.898068),
1407                DelayOld(10),
1408                MoveLR(-1),
1409                MoveUD(0.905911),
1410                DelayOld(20),
1411                MoveUD(0.498062),
1412                DelayOld(20),
1413                MoveUD(0.0274667),
1414                MoveUD(-0.403912),
1415                DelayOld(20),
1416                MoveUD(-1),
1417                Run(release=False),
1418                Jump(release=False),
1419                DelayOld(10),
1420                Punch(release=False),
1421                DelayOld(70),
1422                JumpRelease(),
1423                DelayOld(110),
1424                MoveLR(-0.976501),
1425                RunRelease(),
1426                PunchRelease(),
1427                DelayOld(10),
1428                MoveLR(-0.952971),
1429                DelayOld(20),
1430                MoveLR(-0.905911),
1431                MoveLR(-0.827479),
1432                DelayOld(20),
1433                MoveLR(-0.75689),
1434                DelayOld(30),
1435                MoveLR(-0.73336),
1436                MoveLR(-0.694143),
1437                DelayOld(20),
1438                MoveLR(-0.670614),
1439                DelayOld(30),
1440                MoveLR(-0.66277),
1441                DelayOld(10),
1442                MoveUD(-0.960784),
1443                DelayOld(20),
1444                MoveLR(-0.623554),
1445                MoveUD(-0.874508),
1446                DelayOld(10),
1447                MoveLR(-0.545122),
1448                MoveUD(-0.694113),
1449                DelayOld(20),
1450                MoveLR(-0.505905),
1451                MoveUD(-0.474502),
1452                DelayOld(20),
1453                MoveLR(-0.458846),
1454                MoveUD(-0.356853),
1455                MoveLR(-0.364727),
1456                MoveUD(-0.27842),
1457                DelayOld(20),
1458                MoveLR(0.00390637),
1459                Move(0, 0),
1460                DelayOld(1000),
1461                Text(ba.Lstr(resource=self._r +
1462                             '.phrase09Text')),  # ah that's better
1463                DelayOld(1900),
1464                AnalyticsScreen('Tutorial Section 3'),
1465                Text(ba.Lstr(resource=self._r +
1466                             '.phrase10Text')),  # running also helps
1467                DelayOld(100),
1468                SpawnSpaz(0, (-3.2, 4.3, -4.4), make_current=True,
1469                          flash=False),
1470                SpawnSpaz(1, (3.3, 4.2, -5.8),
1471                          make_current=False,
1472                          color=(0.9, 0.5, 1.0),
1473                          name=ba.Lstr(resource=self._r + '.randomName2Text')),
1474                DelayOld(1800),
1475                Text(ba.Lstr(resource=self._r +
1476                             '.phrase11Text')),  # hold ANY button to run
1477                DelayOld(300),
1478                MoveUD(0),
1479                DelayOld(20),
1480                MoveUD(-0.0520646),
1481                DelayOld(20),
1482                MoveLR(0),
1483                MoveUD(-0.223518),
1484                Run(release=False),
1485                Jump(release=False),
1486                DelayOld(10),
1487                MoveLR(0.0980255),
1488                MoveUD(-0.309793),
1489                DelayOld(30),
1490                MoveLR(0.160772),
1491                MoveUD(-0.427442),
1492                DelayOld(20),
1493                MoveLR(0.231361),
1494                MoveUD(-0.545091),
1495                DelayOld(10),
1496                MoveLR(0.317637),
1497                MoveUD(-0.678426),
1498                DelayOld(20),
1499                MoveLR(0.396069),
1500                MoveUD(-0.819605),
1501                MoveLR(0.482345),
1502                MoveUD(-0.913724),
1503                DelayOld(20),
1504                MoveLR(0.560778),
1505                MoveUD(-1),
1506                DelayOld(20),
1507                MoveLR(0.607837),
1508                DelayOld(10),
1509                MoveLR(0.623524),
1510                DelayOld(30),
1511                MoveLR(0.647053),
1512                DelayOld(20),
1513                MoveLR(0.670583),
1514                MoveLR(0.694113),
1515                DelayOld(30),
1516                MoveLR(0.733329),
1517                DelayOld(20),
1518                MoveLR(0.764702),
1519                MoveLR(0.788232),
1520                DelayOld(20),
1521                MoveLR(0.827448),
1522                DelayOld(10),
1523                MoveLR(0.858821),
1524                DelayOld(20),
1525                MoveLR(0.921567),
1526                DelayOld(30),
1527                MoveLR(0.97647),
1528                MoveLR(1),
1529                DelayOld(130),
1530                MoveUD(-0.960784),
1531                DelayOld(20),
1532                MoveUD(-0.921567),
1533                DelayOld(30),
1534                MoveUD(-0.866665),
1535                MoveUD(-0.819605),
1536                DelayOld(30),
1537                MoveUD(-0.772546),
1538                MoveUD(-0.725486),
1539                DelayOld(30),
1540                MoveUD(-0.631367),
1541                DelayOld(10),
1542                MoveUD(-0.552934),
1543                DelayOld(20),
1544                MoveUD(-0.474502),
1545                DelayOld(10),
1546                MoveUD(-0.403912),
1547                DelayOld(30),
1548                MoveUD(-0.356853),
1549                DelayOld(30),
1550                MoveUD(-0.34901),
1551                DelayOld(20),
1552                MoveUD(-0.333323),
1553                DelayOld(20),
1554                MoveUD(-0.32548),
1555                DelayOld(10),
1556                MoveUD(-0.30195),
1557                DelayOld(20),
1558                MoveUD(-0.27842),
1559                DelayOld(30),
1560                MoveUD(-0.254891),
1561                MoveUD(-0.231361),
1562                DelayOld(30),
1563                MoveUD(-0.207831),
1564                DelayOld(20),
1565                MoveUD(-0.199988),
1566                MoveUD(-0.176458),
1567                DelayOld(30),
1568                MoveUD(-0.137242),
1569                MoveUD(-0.0823389),
1570                DelayOld(20),
1571                MoveUD(-0.0274361),
1572                DelayOld(20),
1573                MoveUD(0.00393689),
1574                DelayOld(40),
1575                MoveUD(0.0353099),
1576                DelayOld(20),
1577                MoveUD(0.113742),
1578                DelayOld(10),
1579                MoveUD(0.137272),
1580                DelayOld(20),
1581                MoveUD(0.160802),
1582                MoveUD(0.184332),
1583                DelayOld(20),
1584                MoveUD(0.207862),
1585                DelayOld(30),
1586                MoveUD(0.247078),
1587                MoveUD(0.262764),
1588                DelayOld(20),
1589                MoveUD(0.270608),
1590                DelayOld(30),
1591                MoveUD(0.294137),
1592                MoveUD(0.32551),
1593                DelayOld(30),
1594                MoveUD(0.37257),
1595                Celebrate('left', 1),
1596                DelayOld(20),
1597                MoveUD(0.498062),
1598                MoveUD(0.560808),
1599                DelayOld(30),
1600                MoveUD(0.654927),
1601                MoveUD(0.694143),
1602                DelayOld(30),
1603                MoveUD(0.741203),
1604                DelayOld(20),
1605                MoveUD(0.780419),
1606                MoveUD(0.819636),
1607                DelayOld(20),
1608                MoveUD(0.843165),
1609                DelayOld(20),
1610                MoveUD(0.882382),
1611                DelayOld(10),
1612                MoveUD(0.913755),
1613                DelayOld(30),
1614                MoveUD(0.968657),
1615                MoveUD(1),
1616                DelayOld(560),
1617                Punch(release=False),
1618                DelayOld(210),
1619                MoveUD(0.968657),
1620                DelayOld(30),
1621                MoveUD(0.75689),
1622                PunchRelease(),
1623                DelayOld(20),
1624                MoveLR(0.95294),
1625                MoveUD(0.435316),
1626                RunRelease(),
1627                JumpRelease(),
1628                MoveLR(0.811762),
1629                MoveUD(0.270608),
1630                DelayOld(20),
1631                MoveLR(0.670583),
1632                MoveUD(0.160802),
1633                DelayOld(20),
1634                MoveLR(0.466659),
1635                MoveUD(0.0588397),
1636                DelayOld(10),
1637                MoveLR(0.317637),
1638                MoveUD(-0.00390637),
1639                DelayOld(20),
1640                MoveLR(0.0801416),
1641                DelayOld(10),
1642                MoveLR(0),
1643                DelayOld(20),
1644                MoveLR(0),
1645                DelayOld(30),
1646                MoveLR(0),
1647                DelayOld(30),
1648                MoveLR(0),
1649                DelayOld(20),
1650                MoveLR(0),
1651                DelayOld(100),
1652                MoveLR(0),
1653                DelayOld(30),
1654                MoveUD(0),
1655                DelayOld(30),
1656                MoveUD(0),
1657                DelayOld(50),
1658                MoveUD(0),
1659                MoveUD(0),
1660                DelayOld(30),
1661                MoveLR(0),
1662                MoveUD(-0.0520646),
1663                MoveLR(0),
1664                MoveUD(-0.0640889),
1665                DelayOld(20),
1666                MoveLR(0),
1667                MoveUD(-0.0881375),
1668                DelayOld(30),
1669                MoveLR(-0.0498978),
1670                MoveUD(-0.199988),
1671                MoveLR(-0.121586),
1672                MoveUD(-0.207831),
1673                DelayOld(20),
1674                MoveLR(-0.145116),
1675                MoveUD(-0.223518),
1676                DelayOld(30),
1677                MoveLR(-0.152959),
1678                MoveUD(-0.231361),
1679                MoveLR(-0.192175),
1680                MoveUD(-0.262734),
1681                DelayOld(30),
1682                MoveLR(-0.200018),
1683                MoveUD(-0.27842),
1684                DelayOld(20),
1685                MoveLR(-0.239235),
1686                MoveUD(-0.30195),
1687                MoveUD(-0.309793),
1688                DelayOld(40),
1689                MoveUD(-0.333323),
1690                DelayOld(10),
1691                MoveUD(-0.34901),
1692                DelayOld(30),
1693                MoveUD(-0.372539),
1694                MoveUD(-0.396069),
1695                DelayOld(20),
1696                MoveUD(-0.443129),
1697                DelayOld(20),
1698                MoveUD(-0.458815),
1699                DelayOld(10),
1700                MoveUD(-0.474502),
1701                DelayOld(50),
1702                MoveUD(-0.482345),
1703                DelayOld(30),
1704                MoveLR(-0.215705),
1705                DelayOld(30),
1706                MoveLR(-0.200018),
1707                DelayOld(10),
1708                MoveLR(-0.192175),
1709                DelayOld(10),
1710                MoveLR(-0.176489),
1711                DelayOld(30),
1712                MoveLR(-0.152959),
1713                DelayOld(20),
1714                MoveLR(-0.145116),
1715                MoveLR(-0.121586),
1716                MoveUD(-0.458815),
1717                DelayOld(30),
1718                MoveLR(-0.098056),
1719                MoveUD(-0.419599),
1720                DelayOld(10),
1721                MoveLR(-0.0745262),
1722                MoveUD(-0.333323),
1723                DelayOld(10),
1724                MoveLR(0.00390637),
1725                MoveUD(0),
1726                DelayOld(990),
1727                MoveLR(0),
1728                DelayOld(660),
1729                MoveUD(0),
1730                AnalyticsScreen('Tutorial Section 4'),
1731                Text(
1732                    ba.Lstr(resource=self._r +
1733                            '.phrase12Text')),  # for extra-awesome punches,...
1734                DelayOld(200),
1735                SpawnSpaz(
1736                    0,
1737                    (2.368781805038452, 4.337533950805664, -4.360159873962402),
1738                    make_current=True,
1739                    flash=False),
1740                SpawnSpaz(
1741                    1,
1742                    (-3.2, 4.3, -4.5),
1743                    make_current=False,
1744                    color=(1.0, 0.7, 0.3),
1745                    # name=R.randomName3Text),
1746                    name=ba.Lstr(resource=self._r + '.randomName3Text')),
1747                DelayOld(100),
1748                Powerup(1, (2.5, 0.0, 0), relative_to=0),
1749                Move(1, 0),
1750                DelayOld(1700),
1751                Move(0, -0.1),
1752                DelayOld(100),
1753                Move(0, 0),
1754                DelayOld(500),
1755                DelayOld(320),
1756                MoveLR(0),
1757                DelayOld(20),
1758                MoveLR(0),
1759                DelayOld(10),
1760                MoveLR(0),
1761                DelayOld(20),
1762                MoveLR(-0.333354),
1763                MoveLR(-0.592181),
1764                DelayOld(20),
1765                MoveLR(-0.788263),
1766                DelayOld(20),
1767                MoveLR(-1),
1768                MoveUD(0.0353099),
1769                MoveUD(0.0588397),
1770                DelayOld(10),
1771                Run(release=False),
1772                DelayOld(780),
1773                MoveUD(0.0274667),
1774                MoveUD(0.00393689),
1775                DelayOld(10),
1776                MoveUD(-0.00390637),
1777                DelayOld(440),
1778                MoveUD(0.0353099),
1779                DelayOld(20),
1780                MoveUD(0.0588397),
1781                DelayOld(10),
1782                MoveUD(0.0902127),
1783                DelayOld(260),
1784                MoveUD(0.0353099),
1785                DelayOld(30),
1786                MoveUD(0.00393689),
1787                DelayOld(10),
1788                MoveUD(-0.00390637),
1789                MoveUD(-0.0274361),
1790                Celebrate('left', 1),
1791                DelayOld(10),
1792                MoveUD(-0.0823389),
1793                DelayOld(30),
1794                MoveUD(-0.176458),
1795                MoveUD(-0.286264),
1796                DelayOld(20),
1797                MoveUD(-0.498032),
1798                Jump(release=False),
1799                MoveUD(-0.764702),
1800                DelayOld(30),
1801                MoveLR(-0.858852),
1802                MoveUD(-1),
1803                MoveLR(-0.780419),
1804                DelayOld(20),
1805                MoveLR(-0.717673),
1806                DelayOld(10),
1807                MoveLR(-0.552965),
1808                DelayOld(10),
1809                MoveLR(-0.341197),
1810                DelayOld(10),
1811                MoveLR(-0.0274667),
1812                DelayOld(10),
1813                MoveLR(0.27842),
1814                DelayOld(20),
1815                MoveLR(0.811762),
1816                MoveLR(1),
1817                RunRelease(),
1818                JumpRelease(),
1819                DelayOld(260),
1820                MoveLR(0.95294),
1821                DelayOld(30),
1822                MoveLR(0.756859),
1823                DelayOld(10),
1824                MoveLR(0.317637),
1825                MoveLR(-0.00393689),
1826                DelayOld(10),
1827                MoveLR(-0.341197),
1828                DelayOld(10),
1829                MoveLR(-0.647084),
1830                MoveUD(-0.921567),
1831                DelayOld(10),
1832                MoveLR(-1),
1833                MoveUD(-0.599994),
1834                MoveUD(-0.474502),
1835                DelayOld(10),
1836                MoveUD(-0.309793),
1837                DelayOld(10),
1838                MoveUD(-0.160772),
1839                MoveUD(-0.0352794),
1840                Delay(10),
1841                MoveUD(0.176489),
1842                Delay(10),
1843                MoveUD(0.607868),
1844                Run(release=False),
1845                Jump(release=False),
1846                DelayOld(20),
1847                MoveUD(1),
1848                DelayOld(30),
1849                MoveLR(-0.921598),
1850                DelayOld(10),
1851                Punch(release=False),
1852                MoveLR(-0.639241),
1853                DelayOld(10),
1854                MoveLR(-0.223548),
1855                DelayOld(10),
1856                MoveLR(0.254891),
1857                DelayOld(10),
1858                MoveLR(0.741172),
1859                MoveLR(1),
1860                DelayOld(40),
1861                JumpRelease(),
1862                DelayOld(40),
1863                MoveUD(0.976501),
1864                DelayOld(10),
1865                MoveUD(0.73336),
1866                DelayOld(10),
1867                MoveUD(0.309824),
1868                DelayOld(20),
1869                MoveUD(-0.184301),
1870                DelayOld(20),
1871                MoveUD(-0.811762),
1872                MoveUD(-1),
1873                KillSpaz(1, explode=True),
1874                DelayOld(10),
1875                RunRelease(),
1876                PunchRelease(),
1877                DelayOld(110),
1878                MoveLR(0.97647),
1879                MoveLR(0.898038),
1880                DelayOld(20),
1881                MoveLR(0.788232),
1882                DelayOld(20),
1883                MoveLR(0.670583),
1884                DelayOld(10),
1885                MoveLR(0.505875),
1886                DelayOld(10),
1887                MoveLR(0.32548),
1888                DelayOld(20),
1889                MoveLR(0.137242),
1890                DelayOld(10),
1891                MoveLR(-0.00393689),
1892                DelayOld(10),
1893                MoveLR(-0.215705),
1894                MoveLR(-0.356883),
1895                DelayOld(20),
1896                MoveLR(-0.451003),
1897                DelayOld(10),
1898                MoveLR(-0.552965),
1899                DelayOld(20),
1900                MoveLR(-0.670614),
1901                MoveLR(-0.780419),
1902                DelayOld(10),
1903                MoveLR(-0.898068),
1904                DelayOld(20),
1905                MoveLR(-1),
1906                DelayOld(370),
1907                MoveLR(-0.976501),
1908                DelayOld(10),
1909                MoveLR(-0.952971),
1910                DelayOld(10),
1911                MoveLR(-0.929441),
1912                MoveLR(-0.898068),
1913                DelayOld(30),
1914                MoveLR(-0.874538),
1915                DelayOld(10),
1916                MoveLR(-0.851009),
1917                DelayOld(10),
1918                MoveLR(-0.835322),
1919                MoveUD(-0.968627),
1920                DelayOld(10),
1921                MoveLR(-0.827479),
1922                MoveUD(-0.960784),
1923                DelayOld(20),
1924                MoveUD(-0.945097),
1925                DelayOld(70),
1926                MoveUD(-0.937254),
1927                DelayOld(20),
1928                MoveUD(-0.913724),
1929                DelayOld(20),
1930                MoveUD(-0.890194),
1931                MoveLR(-0.780419),
1932                MoveUD(-0.827448),
1933                DelayOld(20),
1934                MoveLR(0.317637),
1935                MoveUD(0.3961),
1936                MoveLR(0.0195929),
1937                MoveUD(0.056093),
1938                DelayOld(20),
1939                MoveUD(0),
1940                DelayOld(750),
1941                MoveLR(0),
1942                Text(
1943                    ba.Lstr(resource=self._r + '.phrase13Text',
1944                            subs=[('${NAME}',
1945                                   ba.Lstr(resource=self._r +
1946                                           '.randomName3Text'))
1947                                  ])),  # whoops sorry bill
1948                RemoveGloves(),
1949                DelayOld(2000),
1950                AnalyticsScreen('Tutorial Section 5'),
1951                Text(
1952                    ba.Lstr(resource=self._r + '.phrase14Text',
1953                            subs=[('${NAME}',
1954                                   ba.Lstr(resource=self._r +
1955                                           '.randomName4Text'))])
1956                ),  # you can pick up and throw things such as chuck here
1957                SpawnSpaz(0, (-4.0, 4.3, -2.5),
1958                          make_current=True,
1959                          flash=False,
1960                          angle=90),
1961                SpawnSpaz(1, (5, 0, -1.0),
1962                          relative_to=0,
1963                          make_current=False,
1964                          color=(0.4, 1.0, 0.7),
1965                          name=ba.Lstr(resource=self._r + '.randomName4Text')),
1966                DelayOld(1000),
1967                Celebrate('left', 1, duration=1000),
1968                Move(1, 0.2),
1969                DelayOld(2000),
1970                PickUp(),
1971                DelayOld(200),
1972                Move(0.5, 1.0),
1973                DelayOld(1200),
1974                PickUp(),
1975                Move(0, 0),
1976                DelayOld(1000),
1977                Celebrate('left'),
1978                DelayOld(1500),
1979                Move(0, -1.0),
1980                DelayOld(800),
1981                Move(0, 0),
1982                DelayOld(800),
1983                SpawnSpaz(0, (1.5, 4.3, -4.0),
1984                          make_current=True,
1985                          flash=False,
1986                          angle=0),
1987                AnalyticsScreen('Tutorial Section 6'),
1988                Text(ba.Lstr(resource=self._r +
1989                             '.phrase15Text')),  # lastly there's bombs
1990                DelayOld(1900),
1991                Text(
1992                    ba.Lstr(resource=self._r +
1993                            '.phrase16Text')),  # throwing bombs takes practice
1994                DelayOld(2000),
1995                Bomb(),
1996                Move(-0.1, -0.1),
1997                DelayOld(100),
1998                Move(0, 0),
1999                DelayOld(500),
2000                DelayOld(1000),
2001                Bomb(),
2002                DelayOld(2000),
2003                Text(ba.Lstr(resource=self._r +
2004                             '.phrase17Text')),  # not a very good throw
2005                DelayOld(3000),
2006                Text(
2007                    ba.Lstr(resource=self._r +
2008                            '.phrase18Text')),  # moving helps you get distance
2009                DelayOld(1000),
2010                Bomb(),
2011                DelayOld(500),
2012                Move(-0.3, 0),
2013                DelayOld(100),
2014                Move(-0.6, 0),
2015                DelayOld(100),
2016                Move(-1, 0),
2017                DelayOld(800),
2018                Bomb(),
2019                DelayOld(400),
2020                Move(0, -0.1),
2021                DelayOld(100),
2022                Move(0, 0),
2023                DelayOld(2500),
2024                Text(ba.Lstr(resource=self._r +
2025                             '.phrase19Text')),  # jumping helps you get height
2026                DelayOld(2000),
2027                Bomb(),
2028                DelayOld(500),
2029                Move(1, 0),
2030                DelayOld(300),
2031                Jump(release_delay=250),
2032                DelayOld(500),
2033                Jump(release_delay=250),
2034                DelayOld(550),
2035                Jump(release_delay=250),
2036                DelayOld(160),
2037                Punch(),
2038                DelayOld(500),
2039                Move(0, -0.1),
2040                DelayOld(100),
2041                Move(0, 0),
2042                DelayOld(2000),
2043                Text(ba.Lstr(resource=self._r +
2044                             '.phrase20Text')),  # whiplash your bombs
2045                DelayOld(1000),
2046                Bomb(release=False),
2047                DelayOld2(80),
2048                RunRelease(),
2049                BombRelease(),
2050                DelayOld2(620),
2051                MoveLR(0),
2052                DelayOld2(10),
2053                MoveLR(0),
2054                DelayOld2(40),
2055                MoveLR(0),
2056                DelayOld2(10),
2057                MoveLR(-0.0537431),
2058                MoveUD(0),
2059                DelayOld2(20),
2060                MoveLR(-0.262764),
2061                DelayOld2(20),
2062                MoveLR(-0.498062),
2063                DelayOld2(10),
2064                MoveLR(-0.639241),
2065                DelayOld2(20),
2066                MoveLR(-0.73336),
2067                DelayOld2(10),
2068                MoveLR(-0.843165),
2069                MoveUD(-0.0352794),
2070                DelayOld2(30),
2071                MoveLR(-1),
2072                DelayOld2(10),
2073                MoveUD(-0.0588092),
2074                DelayOld2(10),
2075                MoveUD(-0.160772),
2076                DelayOld2(20),
2077                MoveUD(-0.286264),
2078                DelayOld2(20),
2079                MoveUD(-0.427442),
2080                DelayOld2(10),
2081                MoveUD(-0.623524),
2082                DelayOld2(20),
2083                MoveUD(-0.843135),
2084                DelayOld2(10),
2085                MoveUD(-1),
2086                DelayOld2(40),
2087                MoveLR(-0.890225),
2088                DelayOld2(10),
2089                MoveLR(-0.670614),
2090                DelayOld2(20),
2091                MoveLR(-0.435316),
2092                DelayOld2(20),
2093                MoveLR(-0.184332),
2094                DelayOld2(10),
2095                MoveLR(0.00390637),
2096                DelayOld2(20),
2097                MoveLR(0.223518),
2098                DelayOld2(10),
2099                MoveLR(0.388226),
2100                DelayOld2(20),
2101                MoveLR(0.560778),
2102                DelayOld2(20),
2103                MoveLR(0.717643),
2104                DelayOld2(10),
2105                MoveLR(0.890194),
2106                DelayOld2(20),
2107                MoveLR(1),
2108                DelayOld2(30),
2109                MoveUD(-0.968627),
2110                DelayOld2(20),
2111                MoveUD(-0.898038),
2112                DelayOld2(10),
2113                MoveUD(-0.741172),
2114                DelayOld2(20),
2115                MoveUD(-0.498032),
2116                DelayOld2(20),
2117                MoveUD(-0.247047),
2118                DelayOld2(10),
2119                MoveUD(0.00393689),
2120                DelayOld2(20),
2121                MoveUD(0.239235),
2122                DelayOld2(20),
2123                MoveUD(0.458846),
2124                DelayOld2(10),
2125                MoveUD(0.70983),
2126                DelayOld2(30),
2127                MoveUD(1),
2128                DelayOld2(10),
2129                MoveLR(0.827448),
2130                DelayOld2(10),
2131                MoveLR(0.678426),
2132                DelayOld2(20),
2133                MoveLR(0.396069),
2134                DelayOld2(10),
2135                MoveLR(0.0980255),
2136                DelayOld2(20),
2137                MoveLR(-0.160802),
2138                DelayOld2(20),
2139                MoveLR(-0.388256),
2140                DelayOld2(10),
2141                MoveLR(-0.545122),
2142                DelayOld2(30),
2143                MoveLR(-0.73336),
2144                DelayOld2(10),
2145                MoveLR(-0.945128),
2146                DelayOld2(10),
2147                MoveLR(-1),
2148                DelayOld2(50),
2149                MoveUD(0.960814),
2150                DelayOld2(20),
2151                MoveUD(0.890225),
2152                DelayOld2(10),
2153                MoveUD(0.749046),
2154                DelayOld2(20),
2155                MoveUD(0.623554),
2156                DelayOld2(20),
2157                MoveUD(0.498062),
2158                DelayOld2(10),
2159                MoveUD(0.34904),
2160                DelayOld2(20),
2161                MoveUD(0.239235),
2162                DelayOld2(20),
2163                MoveUD(0.137272),
2164                DelayOld2(10),
2165                MoveUD(0.0117801),
2166                DelayOld2(20),
2167                MoveUD(-0.0117496),
2168                DelayOld2(10),
2169                MoveUD(-0.0274361),
2170                DelayOld2(90),
2171                MoveUD(-0.0352794),
2172                Run(release=False),
2173                Jump(release=False),
2174                Delay(80),
2175                Punch(release=False),
2176                DelayOld2(60),
2177                MoveLR(-0.968657),
2178                DelayOld2(20),
2179                MoveLR(-0.835322),
2180                DelayOld2(10),
2181                MoveLR(-0.70983),
2182                JumpRelease(),
2183                DelayOld2(30),
2184                MoveLR(-0.592181),
2185                MoveUD(-0.0588092),
2186                DelayOld2(10),
2187                MoveLR(-0.490219),
2188                MoveUD(-0.0744957),
2189                DelayOld2(10),
2190                MoveLR(-0.41963),
2191                DelayOld2(20),
2192                MoveLR(0),
2193                MoveUD(0),
2194                DelayOld2(20),
2195                MoveUD(0),
2196                PunchRelease(),
2197                RunRelease(),
2198                DelayOld(500),
2199                Move(0, -0.1),
2200                DelayOld(100),
2201                Move(0, 0),
2202                DelayOld(2000),
2203                AnalyticsScreen('Tutorial Section 7'),
2204                Text(ba.Lstr(
2205                    resource=self._r +
2206                    '.phrase21Text')),  # timing your bombs can be tricky
2207                Move(-1, 0),
2208                DelayOld(1000),
2209                Move(0, -0.1),
2210                DelayOld(100),
2211                Move(0, 0),
2212                SpawnSpaz(0, (-0.7, 4.3, -3.9),
2213                          make_current=True,
2214                          flash=False,
2215                          angle=-30),
2216                SpawnSpaz(1, (6.5, 0, -0.75),
2217                          relative_to=0,
2218                          make_current=False,
2219                          color=(0.3, 0.8, 1.0),
2220                          name=ba.Lstr(resource=self._r + '.randomName5Text')),
2221                DelayOld2(1000),
2222                Move(-1, 0),
2223                DelayOld2(1800),
2224                Bomb(),
2225                Move(0, 0),
2226                DelayOld2(300),
2227                Move(1, 0),
2228                DelayOld2(600),
2229                Jump(),
2230                DelayOld2(150),
2231                Punch(),
2232                DelayOld2(800),
2233                Move(-1, 0),
2234                DelayOld2(1000),
2235                Move(0, 0),
2236                DelayOld2(1500),
2237                Text(ba.Lstr(resource=self._r + '.phrase22Text')),  # dang
2238                Delay(1500),
2239                Text(''),
2240                Delay(200),
2241                Text(ba.Lstr(resource=self._r +
2242                             '.phrase23Text')),  # try cooking off
2243                Delay(1500),
2244                Bomb(),
2245                Delay(800),
2246                Move(1, 0.12),
2247                Delay(1100),
2248                Jump(),
2249                Delay(100),
2250                Punch(),
2251                Delay(100),
2252                Move(0, -0.1),
2253                Delay(100),
2254                Move(0, 0),
2255                Delay(2000),
2256                Text(ba.Lstr(resource=self._r +
2257                             '.phrase24Text')),  # hooray nicely cooked
2258                Celebrate(),
2259                DelayOld(2000),
2260                KillSpaz(1),
2261                Text(''),
2262                Move(0.5, -0.5),
2263                DelayOld(1000),
2264                Move(0, -0.1),
2265                DelayOld(100),
2266                Move(0, 0),
2267                DelayOld(1000),
2268                AnalyticsScreen('Tutorial Section 8'),
2269                Text(ba.Lstr(resource=self._r +
2270                             '.phrase25Text')),  # well that's just about it
2271                DelayOld(2000),
2272                Text(ba.Lstr(resource=self._r +
2273                             '.phrase26Text')),  # go get em tiger
2274                DelayOld(2000),
2275                Text(ba.Lstr(resource=self._r +
2276                             '.phrase27Text')),  # remember you training
2277                DelayOld(3000),
2278                Text(ba.Lstr(resource=self._r +
2279                             '.phrase28Text')),  # well maybe
2280                DelayOld(1600),
2281                Text(ba.Lstr(resource=self._r + '.phrase29Text')),  # good luck
2282                Celebrate('right', duration=10000),
2283                DelayOld(1000),
2284                AnalyticsScreen('Tutorial Complete'),
2285                End(),
2286            ]
2287
2288        except Exception:
2289            ba.print_exception()
2290
2291        # If we read some, exec them.
2292        if self._entries:
2293            self._run_next_entry()
2294        # Otherwise try again in a few seconds.
2295        else:
2296            self._read_entries_timer = ba.Timer(
2297                3.0, ba.WeakCall(self._read_entries))
2298
2299    def _run_next_entry(self) -> None:
2300
2301        while self._entries:
2302            entry = self._entries.pop(0)
2303            try:
2304                result = entry.run(self)
2305            except Exception:
2306                result = None
2307                ba.print_exception()
2308
2309            # If the entry returns an int value, set a timer;
2310            # otherwise just keep going.
2311            if result is not None:
2312                self._entry_timer = ba.Timer(
2313                    result,
2314                    ba.WeakCall(self._run_next_entry),
2315                    timeformat=ba.TimeFormat.MILLISECONDS)
2316                return
2317
2318        # Done with these entries.. start over soon.
2319        self._read_entries_timer = ba.Timer(1.0,
2320                                            ba.WeakCall(self._read_entries))
2321
2322    def _update_skip_votes(self) -> None:
2323        count = sum(1 for player in self.players if player.pressed)
2324        assert self._skip_count_text
2325        self._skip_count_text.text = ba.Lstr(
2326            resource=self._r + '.skipVoteCountText',
2327            subs=[('${COUNT}', str(count)),
2328                  ('${TOTAL}', str(len(self.players)))]) if count > 0 else ''
2329        if (count >= len(self.players) and self.players
2330                and not self._have_skipped):
2331            _ba.increment_analytics_count('Tutorial skip')
2332            ba.set_analytics_screen('Tutorial Skip')
2333            self._have_skipped = True
2334            ba.playsound(ba.getsound('swish'))
2335            # self._skip_count_text.text = self._r.skippingText
2336            self._skip_count_text.text = ba.Lstr(resource=self._r +
2337                                                 '.skippingText')
2338            assert self._skip_text
2339            self._skip_text.text = ''
2340            self.end()
2341
2342    def _player_pressed_button(self, player: Player) -> None:
2343
2344        # Special case: if there's only one player, we give them a
2345        # warning on their first press (some players were thinking the
2346        # on-screen guide meant they were supposed to press something).
2347        if len(self.players) == 1 and not self._issued_warning:
2348            self._issued_warning = True
2349            assert self._skip_text
2350            self._skip_text.text = ba.Lstr(resource=self._r +
2351                                           '.skipConfirmText')
2352            self._skip_text.color = (1, 1, 1)
2353            self._skip_text.scale = 1.3
2354            incr = 50
2355            t = incr
2356            for _i in range(6):
2357                ba.timer(t,
2358                         ba.Call(setattr, self._skip_text, 'color',
2359                                 (1, 0.5, 0.1)),
2360                         timeformat=ba.TimeFormat.MILLISECONDS)
2361                t += incr
2362                ba.timer(t,
2363                         ba.Call(setattr, self._skip_text, 'color', (1, 1, 0)),
2364                         timeformat=ba.TimeFormat.MILLISECONDS)
2365                t += incr
2366            ba.timer(6.0, ba.WeakCall(self._revert_confirm))
2367            return
2368
2369        player.pressed = True
2370
2371        # test...
2372        if not all(self.players):
2373            ba.print_error('Nonexistent player in _player_pressed_button: ' +
2374                           str([str(p) for p in self.players]) + ': we are ' +
2375                           str(player))
2376
2377        self._update_skip_votes()
2378
2379    def _revert_confirm(self) -> None:
2380        assert self._skip_text
2381        self._skip_text.text = ba.Lstr(resource=self._r +
2382                                       '.toSkipPressAnythingText')
2383        self._skip_text.color = (1, 1, 1)
2384        self._issued_warning = False
2385
2386    def on_player_join(self, player: Player) -> None:
2387        super().on_player_join(player)
2388
2389        # We just wanna know if this player presses anything.
2390        player.assigninput(
2391            (ba.InputType.JUMP_PRESS, ba.InputType.PUNCH_PRESS,
2392             ba.InputType.BOMB_PRESS, ba.InputType.PICK_UP_PRESS),
2393            ba.Call(self._player_pressed_button, player))
2394
2395    def on_player_leave(self, player: Player) -> None:
2396        if not all(self.players):
2397            ba.print_error('Nonexistent player in on_player_leave: ' +
2398                           str([str(p) for p in self.players]) + ': we are ' +
2399                           str(player))
2400        super().on_player_leave(player)
2401        # our leaving may influence the vote total needed/etc
2402        self._update_skip_votes()
class ButtonPress:
 35class ButtonPress:
 36
 37    def __init__(self,
 38                 button: str,
 39                 delay: int = 0,
 40                 release: bool = True,
 41                 release_delay: int = 0):
 42        self._button = button
 43        self._delay = delay
 44        self._release = release
 45        self._release_delay = release_delay
 46
 47    def run(self, a: TutorialActivity) -> None:
 48        s = a.current_spaz
 49        assert s is not None
 50        img: ba.Node | None
 51        release_call: Callable[[], None] | None
 52        color: Sequence[float] | None
 53        if self._button == 'punch':
 54            call = s.on_punch_press
 55            release_call = s.on_punch_release
 56            img = a.punch_image
 57            color = a.punch_image_color
 58        elif self._button == 'jump':
 59            call = s.on_jump_press
 60            release_call = s.on_jump_release
 61            img = a.jump_image
 62            color = a.jump_image_color
 63        elif self._button == 'bomb':
 64            call = s.on_bomb_press
 65            release_call = s.on_bomb_release
 66            img = a.bomb_image
 67            color = a.bomb_image_color
 68        elif self._button == 'pickUp':
 69            call = s.on_pickup_press
 70            release_call = s.on_pickup_release
 71            img = a.pickup_image
 72            color = a.pickup_image_color
 73        elif self._button == 'run':
 74            call = ba.Call(s.on_run, 1.0)
 75            release_call = ba.Call(s.on_run, 0.0)
 76            img = None
 77            color = None
 78        else:
 79            raise Exception(f'invalid button: {self._button}')
 80
 81        brightness = 4.0
 82        if color is not None:
 83            c_bright = list(color)
 84            c_bright[0] *= brightness
 85            c_bright[1] *= brightness
 86            c_bright[2] *= brightness
 87        else:
 88            c_bright = [1.0, 1.0, 1.0]
 89
 90        if self._delay == 0:
 91            call()
 92            if img is not None:
 93                img.color = c_bright
 94                img.vr_depth = -40
 95        else:
 96            ba.timer(self._delay, call, timeformat=ba.TimeFormat.MILLISECONDS)
 97            if img is not None:
 98                ba.timer(self._delay,
 99                         ba.Call(_safesetattr, img, 'color', c_bright),
100                         timeformat=ba.TimeFormat.MILLISECONDS)
101                ba.timer(self._delay,
102                         ba.Call(_safesetattr, img, 'vr_depth', -30),
103                         timeformat=ba.TimeFormat.MILLISECONDS)
104        if self._release:
105            if self._delay == 0 and self._release_delay == 0:
106                release_call()
107            else:
108                ba.timer(0.001 * (self._delay + self._release_delay),
109                         release_call)
110            if img is not None:
111                ba.timer(self._delay + self._release_delay + 100,
112                         ba.Call(_safesetattr, img, 'color', color),
113                         timeformat=ba.TimeFormat.MILLISECONDS)
114                ba.timer(self._delay + self._release_delay + 100,
115                         ba.Call(_safesetattr, img, 'vr_depth', -20),
116                         timeformat=ba.TimeFormat.MILLISECONDS)
ButtonPress( button: str, delay: int = 0, release: bool = True, release_delay: int = 0)
37    def __init__(self,
38                 button: str,
39                 delay: int = 0,
40                 release: bool = True,
41                 release_delay: int = 0):
42        self._button = button
43        self._delay = delay
44        self._release = release
45        self._release_delay = release_delay
def run(self, a: bastd.tutorial.TutorialActivity) -> None:
 47    def run(self, a: TutorialActivity) -> None:
 48        s = a.current_spaz
 49        assert s is not None
 50        img: ba.Node | None
 51        release_call: Callable[[], None] | None
 52        color: Sequence[float] | None
 53        if self._button == 'punch':
 54            call = s.on_punch_press
 55            release_call = s.on_punch_release
 56            img = a.punch_image
 57            color = a.punch_image_color
 58        elif self._button == 'jump':
 59            call = s.on_jump_press
 60            release_call = s.on_jump_release
 61            img = a.jump_image
 62            color = a.jump_image_color
 63        elif self._button == 'bomb':
 64            call = s.on_bomb_press
 65            release_call = s.on_bomb_release
 66            img = a.bomb_image
 67            color = a.bomb_image_color
 68        elif self._button == 'pickUp':
 69            call = s.on_pickup_press
 70            release_call = s.on_pickup_release
 71            img = a.pickup_image
 72            color = a.pickup_image_color
 73        elif self._button == 'run':
 74            call = ba.Call(s.on_run, 1.0)
 75            release_call = ba.Call(s.on_run, 0.0)
 76            img = None
 77            color = None
 78        else:
 79            raise Exception(f'invalid button: {self._button}')
 80
 81        brightness = 4.0
 82        if color is not None:
 83            c_bright = list(color)
 84            c_bright[0] *= brightness
 85            c_bright[1] *= brightness
 86            c_bright[2] *= brightness
 87        else:
 88            c_bright = [1.0, 1.0, 1.0]
 89
 90        if self._delay == 0:
 91            call()
 92            if img is not None:
 93                img.color = c_bright
 94                img.vr_depth = -40
 95        else:
 96            ba.timer(self._delay, call, timeformat=ba.TimeFormat.MILLISECONDS)
 97            if img is not None:
 98                ba.timer(self._delay,
 99                         ba.Call(_safesetattr, img, 'color', c_bright),
100                         timeformat=ba.TimeFormat.MILLISECONDS)
101                ba.timer(self._delay,
102                         ba.Call(_safesetattr, img, 'vr_depth', -30),
103                         timeformat=ba.TimeFormat.MILLISECONDS)
104        if self._release:
105            if self._delay == 0 and self._release_delay == 0:
106                release_call()
107            else:
108                ba.timer(0.001 * (self._delay + self._release_delay),
109                         release_call)
110            if img is not None:
111                ba.timer(self._delay + self._release_delay + 100,
112                         ba.Call(_safesetattr, img, 'color', color),
113                         timeformat=ba.TimeFormat.MILLISECONDS)
114                ba.timer(self._delay + self._release_delay + 100,
115                         ba.Call(_safesetattr, img, 'vr_depth', -20),
116                         timeformat=ba.TimeFormat.MILLISECONDS)
class ButtonRelease:
119class ButtonRelease:
120
121    def __init__(self, button: str, delay: int = 0):
122        self._button = button
123        self._delay = delay
124
125    def run(self, a: TutorialActivity) -> None:
126        s = a.current_spaz
127        assert s is not None
128        call: Callable[[], None] | None
129        img: ba.Node | None
130        color: Sequence[float] | None
131        if self._button == 'punch':
132            call = s.on_punch_release
133            img = a.punch_image
134            color = a.punch_image_color
135        elif self._button == 'jump':
136            call = s.on_jump_release
137            img = a.jump_image
138            color = a.jump_image_color
139        elif self._button == 'bomb':
140            call = s.on_bomb_release
141            img = a.bomb_image
142            color = a.bomb_image_color
143        elif self._button == 'pickUp':
144            call = s.on_pickup_press
145            img = a.pickup_image
146            color = a.pickup_image_color
147        elif self._button == 'run':
148            call = ba.Call(s.on_run, 0.0)
149            img = None
150            color = None
151        else:
152            raise Exception('invalid button: ' + self._button)
153        if self._delay == 0:
154            call()
155        else:
156            ba.timer(self._delay, call, timeformat=ba.TimeFormat.MILLISECONDS)
157        if img is not None:
158            ba.timer(self._delay + 100,
159                     ba.Call(_safesetattr, img, 'color', color),
160                     timeformat=ba.TimeFormat.MILLISECONDS)
161            ba.timer(self._delay + 100,
162                     ba.Call(_safesetattr, img, 'vr_depth', -20),
163                     timeformat=ba.TimeFormat.MILLISECONDS)
ButtonRelease(button: str, delay: int = 0)
121    def __init__(self, button: str, delay: int = 0):
122        self._button = button
123        self._delay = delay
def run(self, a: bastd.tutorial.TutorialActivity) -> None:
125    def run(self, a: TutorialActivity) -> None:
126        s = a.current_spaz
127        assert s is not None
128        call: Callable[[], None] | None
129        img: ba.Node | None
130        color: Sequence[float] | None
131        if self._button == 'punch':
132            call = s.on_punch_release
133            img = a.punch_image
134            color = a.punch_image_color
135        elif self._button == 'jump':
136            call = s.on_jump_release
137            img = a.jump_image
138            color = a.jump_image_color
139        elif self._button == 'bomb':
140            call = s.on_bomb_release
141            img = a.bomb_image
142            color = a.bomb_image_color
143        elif self._button == 'pickUp':
144            call = s.on_pickup_press
145            img = a.pickup_image
146            color = a.pickup_image_color
147        elif self._button == 'run':
148            call = ba.Call(s.on_run, 0.0)
149            img = None
150            color = None
151        else:
152            raise Exception('invalid button: ' + self._button)
153        if self._delay == 0:
154            call()
155        else:
156            ba.timer(self._delay, call, timeformat=ba.TimeFormat.MILLISECONDS)
157        if img is not None:
158            ba.timer(self._delay + 100,
159                     ba.Call(_safesetattr, img, 'color', color),
160                     timeformat=ba.TimeFormat.MILLISECONDS)
161            ba.timer(self._delay + 100,
162                     ba.Call(_safesetattr, img, 'vr_depth', -20),
163                     timeformat=ba.TimeFormat.MILLISECONDS)
class Player(ba._player.Player[ForwardRef('Team')]):
166class Player(ba.Player['Team']):
167    """Our player type for this game."""
168
169    def __init__(self) -> None:
170        self.pressed = False

Our player type for this game.

Player()
169    def __init__(self) -> None:
170        self.pressed = False
class Team(ba._team.Team[bastd.tutorial.Player]):
173class Team(ba.Team[Player]):
174    """Our team type for this game."""
175
176    def __init__(self) -> None:
177        pass

Our team type for this game.

Team()
176    def __init__(self) -> None:
177        pass
Inherited Members
ba._team.Team
manual_init
customdata
on_expire
sessionteam
class TutorialActivity(ba._activity.Activity[bastd.tutorial.Player, bastd.tutorial.Team]):
 180class TutorialActivity(ba.Activity[Player, Team]):
 181
 182    def __init__(self, settings: dict | None = None):
 183        from bastd.maps import Rampage
 184        if settings is None:
 185            settings = {}
 186        super().__init__(settings)
 187        self.current_spaz: basespaz.Spaz | None = None
 188        self._benchmark_type = getattr(ba.getsession(), 'benchmark_type', None)
 189        self.last_start_time: int | None = None
 190        self.cycle_times: list[int] = []
 191        self.allow_pausing = True
 192        self.allow_kick_idle_players = False
 193        self._issued_warning = False
 194        self._map_type = Rampage
 195        self._map_type.preload()
 196        self._jump_button_tex = ba.gettexture('buttonJump')
 197        self._pick_up_button_tex = ba.gettexture('buttonPickUp')
 198        self._bomb_button_tex = ba.gettexture('buttonBomb')
 199        self._punch_button_tex = ba.gettexture('buttonPunch')
 200        self._r = 'tutorial'
 201        self._have_skipped = False
 202        self.stick_image_position_x = self.stick_image_position_y = 0.0
 203        self.spawn_sound = ba.getsound('spawn')
 204        self.map: ba.Map | None = None
 205        self.text: ba.Node | None = None
 206        self._skip_text: ba.Node | None = None
 207        self._skip_count_text: ba.Node | None = None
 208        self._scale: float | None = None
 209        self._stick_base_position: tuple[float, float] = (0.0, 0.0)
 210        self._stick_nub_position: tuple[float, float] = (0.0, 0.0)
 211        self._stick_base_image_color: Sequence[float] = (1.0, 1.0, 1.0, 1.0)
 212        self._stick_nub_image_color: Sequence[float] = (1.0, 1.0, 1.0, 1.0)
 213        self._time: int = -1
 214        self.punch_image_color = (1.0, 1.0, 1.0)
 215        self.punch_image: ba.Node | None = None
 216        self.bomb_image: ba.Node | None = None
 217        self.jump_image: ba.Node | None = None
 218        self.pickup_image: ba.Node | None = None
 219        self._stick_base_image: ba.Node | None = None
 220        self._stick_nub_image: ba.Node | None = None
 221        self.bomb_image_color = (1.0, 1.0, 1.0)
 222        self.pickup_image_color = (1.0, 1.0, 1.0)
 223        self.control_ui_nodes: list[ba.Node] = []
 224        self.spazzes: dict[int, basespaz.Spaz] = {}
 225        self.jump_image_color = (1.0, 1.0, 1.0)
 226        self._entries: list[Any] = []
 227        self._read_entries_timer: ba.Timer | None = None
 228        self._entry_timer: ba.Timer | None = None
 229
 230    def on_transition_in(self) -> None:
 231        super().on_transition_in()
 232        ba.setmusic(ba.MusicType.CHAR_SELECT, continuous=True)
 233        self.map = self._map_type()
 234
 235    def on_begin(self) -> None:
 236        super().on_begin()
 237
 238        ba.set_analytics_screen('Tutorial Start')
 239        _ba.increment_analytics_count('Tutorial start')
 240
 241        if bool(False):
 242            # Buttons on top.
 243            text_y = 140
 244            buttons_y = 250
 245        else:
 246            # Buttons on bottom.
 247            text_y = 260
 248            buttons_y = 160
 249
 250        # Need different versions of this: taps/buttons/keys.
 251        self.text = ba.newnode('text',
 252                               attrs={
 253                                   'text': '',
 254                                   'scale': 1.9,
 255                                   'position': (0, text_y),
 256                                   'maxwidth': 500,
 257                                   'flatness': 0.0,
 258                                   'shadow': 0.5,
 259                                   'h_align': 'center',
 260                                   'v_align': 'center',
 261                                   'v_attach': 'center'
 262                               })
 263
 264        # Need different versions of this: taps/buttons/keys.
 265        txt = ba.Lstr(
 266            resource=self._r +
 267            '.cpuBenchmarkText') if self._benchmark_type == 'cpu' else ba.Lstr(
 268                resource=self._r + '.toSkipPressAnythingText')
 269        t = self._skip_text = ba.newnode('text',
 270                                         attrs={
 271                                             'text': txt,
 272                                             'maxwidth': 900,
 273                                             'scale': 1.1,
 274                                             'vr_depth': 100,
 275                                             'position': (0, 30),
 276                                             'h_align': 'center',
 277                                             'v_align': 'center',
 278                                             'v_attach': 'bottom'
 279                                         })
 280        ba.animate(t, 'opacity', {1.0: 0.0, 2.0: 0.7})
 281        self._skip_count_text = ba.newnode('text',
 282                                           attrs={
 283                                               'text': '',
 284                                               'scale': 1.4,
 285                                               'vr_depth': 90,
 286                                               'position': (0, 70),
 287                                               'h_align': 'center',
 288                                               'v_align': 'center',
 289                                               'v_attach': 'bottom'
 290                                           })
 291
 292        ouya = False
 293
 294        self._scale = scale = 0.6
 295        center_offs = 130.0 * scale
 296        offs = 65.0 * scale
 297        position = (0, buttons_y)
 298        image_size = 90.0 * scale
 299        image_size_2 = 220.0 * scale
 300        nub_size = 110.0 * scale
 301        p = (position[0] + center_offs, position[1] - offs)
 302
 303        def _sc(r: float, g: float, b: float) -> tuple[float, float, float]:
 304            return 0.6 * r, 0.6 * g, 0.6 * b
 305
 306        self.jump_image_color = c = _sc(0.4, 1, 0.4)
 307        self.jump_image = ba.newnode('image',
 308                                     attrs={
 309                                         'texture': self._jump_button_tex,
 310                                         'absolute_scale': True,
 311                                         'vr_depth': -20,
 312                                         'position': p,
 313                                         'scale': (image_size, image_size),
 314                                         'color': c
 315                                     })
 316        p = (position[0] + center_offs - offs, position[1])
 317        self.punch_image_color = c = _sc(0.2, 0.6, 1) if ouya else _sc(
 318            1, 0.7, 0.3)
 319        self.punch_image = ba.newnode(
 320            'image',
 321            attrs={
 322                'texture': ba.gettexture('buttonPunch'),
 323                'absolute_scale': True,
 324                'vr_depth': -20,
 325                'position': p,
 326                'scale': (image_size, image_size),
 327                'color': c
 328            })
 329        p = (position[0] + center_offs + offs, position[1])
 330        self.bomb_image_color = c = _sc(1, 0.3, 0.3)
 331        self.bomb_image = ba.newnode(
 332            'image',
 333            attrs={
 334                'texture': ba.gettexture('buttonBomb'),
 335                'absolute_scale': True,
 336                'vr_depth': -20,
 337                'position': p,
 338                'scale': (image_size, image_size),
 339                'color': c
 340            })
 341        p = (position[0] + center_offs, position[1] + offs)
 342        self.pickup_image_color = c = _sc(1, 0.8, 0.3) if ouya else _sc(
 343            0.5, 0.5, 1)
 344        self.pickup_image = ba.newnode(
 345            'image',
 346            attrs={
 347                'texture': ba.gettexture('buttonPickUp'),
 348                'absolute_scale': True,
 349                'vr_depth': -20,
 350                'position': p,
 351                'scale': (image_size, image_size),
 352                'color': c
 353            })
 354
 355        self._stick_base_position = p = (position[0] - center_offs,
 356                                         position[1])
 357        self._stick_base_image_color = c2 = (0.25, 0.25, 0.25, 1.0)
 358        self._stick_base_image = ba.newnode(
 359            'image',
 360            attrs={
 361                'texture': ba.gettexture('nub'),
 362                'absolute_scale': True,
 363                'vr_depth': -40,
 364                'position': p,
 365                'scale': (image_size_2, image_size_2),
 366                'color': c2
 367            })
 368        self._stick_nub_position = p = (position[0] - center_offs, position[1])
 369        self._stick_nub_image_color = c3 = (0.4, 0.4, 0.4, 1.0)
 370        self._stick_nub_image = ba.newnode('image',
 371                                           attrs={
 372                                               'texture': ba.gettexture('nub'),
 373                                               'absolute_scale': True,
 374                                               'position': p,
 375                                               'scale': (nub_size, nub_size),
 376                                               'color': c3
 377                                           })
 378        self.control_ui_nodes = [
 379            self.jump_image, self.punch_image, self.bomb_image,
 380            self.pickup_image, self._stick_base_image, self._stick_nub_image
 381        ]
 382        for n in self.control_ui_nodes:
 383            n.opacity = 0.0
 384        self._read_entries()
 385
 386    def set_stick_image_position(self, x: float, y: float) -> None:
 387
 388        # Clamp this to a circle.
 389        len_squared = x * x + y * y
 390        if len_squared > 1.0:
 391            length = math.sqrt(len_squared)
 392            mult = 1.0 / length
 393            x *= mult
 394            y *= mult
 395
 396        self.stick_image_position_x = x
 397        self.stick_image_position_y = y
 398        offs = 50.0
 399        assert self._scale is not None
 400        p = [
 401            self._stick_nub_position[0] + x * offs * self._scale,
 402            self._stick_nub_position[1] + y * offs * self._scale
 403        ]
 404        c = list(self._stick_nub_image_color)
 405        if abs(x) > 0.1 or abs(y) > 0.1:
 406            c[0] *= 2.0
 407            c[1] *= 4.0
 408            c[2] *= 2.0
 409        assert self._stick_nub_image is not None
 410        self._stick_nub_image.position = p
 411        self._stick_nub_image.color = c
 412        c = list(self._stick_base_image_color)
 413        if abs(x) > 0.1 or abs(y) > 0.1:
 414            c[0] *= 1.5
 415            c[1] *= 1.5
 416            c[2] *= 1.5
 417        assert self._stick_base_image is not None
 418        self._stick_base_image.color = c
 419
 420    def _read_entries(self) -> None:
 421        try:
 422
 423            class Reset:
 424
 425                def __init__(self) -> None:
 426                    pass
 427
 428                def run(self, a: TutorialActivity) -> None:
 429
 430                    # if we're looping, print out how long each cycle took
 431                    # print out how long each cycle took..
 432                    if a.last_start_time is not None:
 433                        tval = ba.time(
 434                            ba.TimeType.REAL,
 435                            ba.TimeFormat.MILLISECONDS) - a.last_start_time
 436                        assert isinstance(tval, int)
 437                        diff = tval
 438                        a.cycle_times.append(diff)
 439                        ba.screenmessage(
 440                            'cycle time: ' + str(diff) + ' (average: ' +
 441                            str(sum(a.cycle_times) / len(a.cycle_times)) + ')')
 442                    tval = ba.time(ba.TimeType.REAL,
 443                                   ba.TimeFormat.MILLISECONDS)
 444                    assert isinstance(tval, int)
 445                    a.last_start_time = tval
 446
 447                    assert a.text
 448                    a.text.text = ''
 449                    for spaz in list(a.spazzes.values()):
 450                        spaz.handlemessage(ba.DieMessage(immediate=True))
 451                    a.spazzes = {}
 452                    a.current_spaz = None
 453                    for n in a.control_ui_nodes:
 454                        n.opacity = 0.0
 455                    a.set_stick_image_position(0, 0)
 456
 457            # Can be used for debugging.
 458            class SetSpeed:
 459
 460                def __init__(self, speed: int):
 461                    self._speed = speed
 462
 463                def run(self, a: TutorialActivity) -> None:
 464                    print('setting to', self._speed)
 465                    _ba.set_debug_speed_exponent(self._speed)
 466
 467            class RemoveGloves:
 468
 469                def __init__(self) -> None:
 470                    pass
 471
 472                def run(self, a: TutorialActivity) -> None:
 473                    # pylint: disable=protected-access
 474                    assert a.current_spaz is not None
 475                    # noinspection PyProtectedMember
 476                    a.current_spaz._gloves_wear_off()
 477
 478            class KillSpaz:
 479
 480                def __init__(self, num: int, explode: bool = False):
 481                    self._num = num
 482                    self._explode = explode
 483
 484                def run(self, a: TutorialActivity) -> None:
 485                    if self._explode:
 486                        a.spazzes[self._num].shatter()
 487                    del a.spazzes[self._num]
 488
 489            class SpawnSpaz:
 490
 491                def __init__(self,
 492                             num: int,
 493                             position: Sequence[float],
 494                             color: Sequence[float] = (1.0, 1.0, 1.0),
 495                             make_current: bool = False,
 496                             relative_to: int | None = None,
 497                             name: str | ba.Lstr = '',
 498                             flash: bool = True,
 499                             angle: float = 0.0):
 500                    self._num = num
 501                    self._position = position
 502                    self._make_current = make_current
 503                    self._color = color
 504                    self._relative_to = relative_to
 505                    self._name = name
 506                    self._flash = flash
 507                    self._angle = angle
 508
 509                def run(self, a: TutorialActivity) -> None:
 510
 511                    # if they gave a 'relative to' spaz, position is relative
 512                    # to them
 513                    pos: Sequence[float]
 514                    if self._relative_to is not None:
 515                        snode = a.spazzes[self._relative_to].node
 516                        assert snode
 517                        their_pos = snode.position
 518                        pos = (their_pos[0] + self._position[0],
 519                               their_pos[1] + self._position[1],
 520                               their_pos[2] + self._position[2])
 521                    else:
 522                        pos = self._position
 523
 524                    # if there's already a spaz at this spot, insta-kill it
 525                    if self._num in a.spazzes:
 526                        a.spazzes[self._num].handlemessage(
 527                            ba.DieMessage(immediate=True))
 528
 529                    s = a.spazzes[self._num] = basespaz.Spaz(
 530                        color=self._color,
 531                        start_invincible=self._flash,
 532                        demo_mode=True)
 533
 534                    # FIXME: Should extend spaz to support Lstr names.
 535                    assert s.node
 536                    if isinstance(self._name, ba.Lstr):
 537                        s.node.name = self._name.evaluate()
 538                    else:
 539                        s.node.name = self._name
 540                    s.node.name_color = self._color
 541                    s.handlemessage(ba.StandMessage(pos, self._angle))
 542                    if self._make_current:
 543                        a.current_spaz = s
 544                    if self._flash:
 545                        ba.playsound(a.spawn_sound, position=pos)
 546
 547            class Powerup:
 548
 549                def __init__(self,
 550                             num: int,
 551                             position: Sequence[float],
 552                             color: Sequence[float] = (1.0, 1.0, 1.0),
 553                             make_current: bool = False,
 554                             relative_to: int | None = None):
 555                    self._position = position
 556                    self._relative_to = relative_to
 557
 558                def run(self, a: TutorialActivity) -> None:
 559                    # If they gave a 'relative to' spaz, position is relative
 560                    # to them.
 561                    pos: Sequence[float]
 562                    if self._relative_to is not None:
 563                        snode = a.spazzes[self._relative_to].node
 564                        assert snode
 565                        their_pos = snode.position
 566                        pos = (their_pos[0] + self._position[0],
 567                               their_pos[1] + self._position[1],
 568                               their_pos[2] + self._position[2])
 569                    else:
 570                        pos = self._position
 571                    from bastd.actor import powerupbox
 572                    powerupbox.PowerupBox(position=pos,
 573                                          poweruptype='punch').autoretain()
 574
 575            class Delay:
 576
 577                def __init__(self, time: int) -> None:
 578                    self._time = time
 579
 580                def run(self, a: TutorialActivity) -> int:
 581                    return self._time
 582
 583            class AnalyticsScreen:
 584
 585                def __init__(self, screen: str) -> None:
 586                    self._screen = screen
 587
 588                def run(self, a: TutorialActivity) -> None:
 589                    ba.set_analytics_screen(self._screen)
 590
 591            class DelayOld:
 592
 593                def __init__(self, time: int) -> None:
 594                    self._time = time
 595
 596                def run(self, a: TutorialActivity) -> int:
 597                    return int(0.9 * self._time)
 598
 599            class DelayOld2:
 600
 601                def __init__(self, time: int) -> None:
 602                    self._time = time
 603
 604                def run(self, a: TutorialActivity) -> int:
 605                    return int(0.8 * self._time)
 606
 607            class End:
 608
 609                def __init__(self) -> None:
 610                    pass
 611
 612                def run(self, a: TutorialActivity) -> None:
 613                    _ba.increment_analytics_count('Tutorial finish')
 614                    a.end()
 615
 616            class Move:
 617
 618                def __init__(self, x: float, y: float):
 619                    self._x = float(x)
 620                    self._y = float(y)
 621
 622                def run(self, a: TutorialActivity) -> None:
 623                    s = a.current_spaz
 624                    assert s
 625                    # FIXME: Game should take floats for this.
 626                    x_clamped = self._x
 627                    y_clamped = self._y
 628                    s.on_move_left_right(x_clamped)
 629                    s.on_move_up_down(y_clamped)
 630                    a.set_stick_image_position(self._x, self._y)
 631
 632            class MoveLR:
 633
 634                def __init__(self, x: float):
 635                    self._x = float(x)
 636
 637                def run(self, a: TutorialActivity) -> None:
 638                    s = a.current_spaz
 639                    assert s
 640                    # FIXME: Game should take floats for this.
 641                    x_clamped = self._x
 642                    s.on_move_left_right(x_clamped)
 643                    a.set_stick_image_position(self._x,
 644                                               a.stick_image_position_y)
 645
 646            class MoveUD:
 647
 648                def __init__(self, y: float):
 649                    self._y = float(y)
 650
 651                def run(self, a: TutorialActivity) -> None:
 652                    s = a.current_spaz
 653                    assert s
 654                    # FIXME: Game should take floats for this.
 655                    y_clamped = self._y
 656                    s.on_move_up_down(y_clamped)
 657                    a.set_stick_image_position(a.stick_image_position_x,
 658                                               self._y)
 659
 660            class Bomb(ButtonPress):
 661
 662                def __init__(self,
 663                             delay: int = 0,
 664                             release: bool = True,
 665                             release_delay: int = 500):
 666                    ButtonPress.__init__(self,
 667                                         'bomb',
 668                                         delay=delay,
 669                                         release=release,
 670                                         release_delay=release_delay)
 671
 672            class Jump(ButtonPress):
 673
 674                def __init__(self,
 675                             delay: int = 0,
 676                             release: bool = True,
 677                             release_delay: int = 500):
 678                    ButtonPress.__init__(self,
 679                                         'jump',
 680                                         delay=delay,
 681                                         release=release,
 682                                         release_delay=release_delay)
 683
 684            class Punch(ButtonPress):
 685
 686                def __init__(self,
 687                             delay: int = 0,
 688                             release: bool = True,
 689                             release_delay: int = 500):
 690                    ButtonPress.__init__(self,
 691                                         'punch',
 692                                         delay=delay,
 693                                         release=release,
 694                                         release_delay=release_delay)
 695
 696            class PickUp(ButtonPress):
 697
 698                def __init__(self,
 699                             delay: int = 0,
 700                             release: bool = True,
 701                             release_delay: int = 500):
 702                    ButtonPress.__init__(self,
 703                                         'pickUp',
 704                                         delay=delay,
 705                                         release=release,
 706                                         release_delay=release_delay)
 707
 708            class Run(ButtonPress):
 709
 710                def __init__(self,
 711                             delay: int = 0,
 712                             release: bool = True,
 713                             release_delay: int = 500):
 714                    ButtonPress.__init__(self,
 715                                         'run',
 716                                         delay=delay,
 717                                         release=release,
 718                                         release_delay=release_delay)
 719
 720            class BombRelease(ButtonRelease):
 721
 722                def __init__(self, delay: int = 0):
 723                    super().__init__('bomb', delay=delay)
 724
 725            class JumpRelease(ButtonRelease):
 726
 727                def __init__(self, delay: int = 0):
 728                    super().__init__('jump', delay=delay)
 729
 730            class PunchRelease(ButtonRelease):
 731
 732                def __init__(self, delay: int = 0):
 733                    super().__init__('punch', delay=delay)
 734
 735            class PickUpRelease(ButtonRelease):
 736
 737                def __init__(self, delay: int = 0):
 738                    super().__init__('pickUp', delay=delay)
 739
 740            class RunRelease(ButtonRelease):
 741
 742                def __init__(self, delay: int = 0):
 743                    super().__init__('run', delay=delay)
 744
 745            class ShowControls:
 746
 747                def __init__(self) -> None:
 748                    pass
 749
 750                def run(self, a: TutorialActivity) -> None:
 751                    for n in a.control_ui_nodes:
 752                        ba.animate(n, 'opacity', {0.0: 0.0, 1.0: 1.0})
 753
 754            class Text:
 755
 756                def __init__(self, text: str | ba.Lstr):
 757                    self.text = text
 758
 759                def run(self, a: TutorialActivity) -> None:
 760                    assert a.text
 761                    a.text.text = self.text
 762
 763            class PrintPos:
 764
 765                def __init__(self, spaz_num: int | None = None):
 766                    self._spaz_num = spaz_num
 767
 768                def run(self, a: TutorialActivity) -> None:
 769                    if self._spaz_num is None:
 770                        s = a.current_spaz
 771                    else:
 772                        s = a.spazzes[self._spaz_num]
 773                    assert s and s.node
 774                    t = list(s.node.position)
 775                    print('RestorePos(' + str((t[0], t[1] - 1.0, t[2])) + '),')
 776
 777            class RestorePos:
 778
 779                def __init__(self, pos: Sequence[float]) -> None:
 780                    self._pos = pos
 781
 782                def run(self, a: TutorialActivity) -> None:
 783                    s = a.current_spaz
 784                    assert s
 785                    s.handlemessage(ba.StandMessage(self._pos, 0))
 786
 787            class Celebrate:
 788
 789                def __init__(self,
 790                             celebrate_type: str = 'both',
 791                             spaz_num: int | None = None,
 792                             duration: int = 1000):
 793                    self._spaz_num = spaz_num
 794                    self._celebrate_type = celebrate_type
 795                    self._duration = duration
 796
 797                def run(self, a: TutorialActivity) -> None:
 798                    if self._spaz_num is None:
 799                        s = a.current_spaz
 800                    else:
 801                        s = a.spazzes[self._spaz_num]
 802                    assert s and s.node
 803                    if self._celebrate_type == 'right':
 804                        s.node.handlemessage('celebrate_r', self._duration)
 805                    elif self._celebrate_type == 'left':
 806                        s.node.handlemessage('celebrate_l', self._duration)
 807                    elif self._celebrate_type == 'both':
 808                        s.node.handlemessage('celebrate', self._duration)
 809                    else:
 810                        raise Exception('invalid celebrate type ' +
 811                                        self._celebrate_type)
 812
 813            self._entries = [
 814                Reset(),
 815                SpawnSpaz(0, (0, 5.5, -3.0), make_current=True),
 816                DelayOld(1000),
 817                AnalyticsScreen('Tutorial Section 1'),
 818                Text(ba.Lstr(resource=self._r + '.phrase01Text')),  # hi there
 819                Celebrate('left'),
 820                DelayOld(2000),
 821                Text(
 822                    ba.Lstr(resource=self._r + '.phrase02Text',
 823                            subs=[
 824                                ('${APP_NAME}', ba.Lstr(resource='titleText'))
 825                            ])),  # welcome to <appname>
 826                DelayOld(80),
 827                Run(release=False),
 828                Jump(release=False),
 829                MoveLR(1),
 830                MoveUD(0),
 831                DelayOld(70),
 832                RunRelease(),
 833                JumpRelease(),
 834                DelayOld(60),
 835                MoveUD(1),
 836                DelayOld(30),
 837                MoveLR(0),
 838                DelayOld(90),
 839                MoveLR(-1),
 840                DelayOld(20),
 841                MoveUD(0),
 842                DelayOld(70),
 843                MoveUD(-1),
 844                DelayOld(20),
 845                MoveLR(0),
 846                DelayOld(80),
 847                MoveUD(0),
 848                DelayOld(1500),
 849                Text(ba.Lstr(resource=self._r +
 850                             '.phrase03Text')),  # here's a few tips
 851                DelayOld(1000),
 852                ShowControls(),
 853                DelayOld(1000),
 854                Jump(),
 855                DelayOld(1000),
 856                Jump(),
 857                DelayOld(1000),
 858                AnalyticsScreen('Tutorial Section 2'),
 859                Text(
 860                    ba.Lstr(resource=self._r + '.phrase04Text',
 861                            subs=[
 862                                ('${APP_NAME}', ba.Lstr(resource='titleText'))
 863                            ])),  # many things are based on physics
 864                DelayOld(20),
 865                MoveUD(0),
 866                DelayOld(60),
 867                MoveLR(0),
 868                DelayOld(10),
 869                MoveLR(0),
 870                MoveUD(0),
 871                DelayOld(10),
 872                MoveLR(0),
 873                MoveUD(0),
 874                DelayOld(20),
 875                MoveUD(-0.0575579),
 876                DelayOld(10),
 877                MoveUD(-0.207831),
 878                DelayOld(30),
 879                MoveUD(-0.309793),
 880                DelayOld(10),
 881                MoveUD(-0.474502),
 882                DelayOld(10),
 883                MoveLR(0.00390637),
 884                MoveUD(-0.647053),
 885                DelayOld(20),
 886                MoveLR(-0.0745262),
 887                MoveUD(-0.819605),
 888                DelayOld(10),
 889                MoveLR(-0.168645),
 890                MoveUD(-0.937254),
 891                DelayOld(30),
 892                MoveLR(-0.294137),
 893                MoveUD(-1),
 894                DelayOld(10),
 895                MoveLR(-0.411786),
 896                DelayOld(10),
 897                MoveLR(-0.639241),
 898                DelayOld(30),
 899                MoveLR(-0.75689),
 900                DelayOld(10),
 901                MoveLR(-0.905911),
 902                DelayOld(20),
 903                MoveLR(-1),
 904                DelayOld(50),
 905                MoveUD(-0.960784),
 906                DelayOld(20),
 907                MoveUD(-0.819605),
 908                MoveUD(-0.61568),
 909                DelayOld(20),
 910                MoveUD(-0.427442),
 911                DelayOld(20),
 912                MoveUD(-0.231361),
 913                DelayOld(10),
 914                MoveUD(-0.00390637),
 915                DelayOld(30),
 916                MoveUD(0.333354),
 917                MoveUD(0.584338),
 918                DelayOld(20),
 919                MoveUD(0.764733),
 920                DelayOld(30),
 921                MoveLR(-0.803949),
 922                MoveUD(0.913755),
 923                DelayOld(10),
 924                MoveLR(-0.647084),
 925                MoveUD(0.992187),
 926                DelayOld(20),
 927                MoveLR(-0.435316),
 928                MoveUD(1),
 929                DelayOld(20),
 930                MoveLR(-0.168645),
 931                MoveUD(0.976501),
 932                MoveLR(0.0744957),
 933                MoveUD(0.905911),
 934                DelayOld(20),
 935                MoveLR(0.270577),
 936                MoveUD(0.843165),
 937                DelayOld(20),
 938                MoveLR(0.435286),
 939                MoveUD(0.780419),
 940                DelayOld(10),
 941                MoveLR(0.66274),
 942                MoveUD(0.647084),
 943                DelayOld(30),
 944                MoveLR(0.803919),
 945                MoveUD(0.458846),
 946                MoveLR(0.929411),
 947                MoveUD(0.223548),
 948                DelayOld(20),
 949                MoveLR(0.95294),
 950                MoveUD(0.137272),
 951                DelayOld(20),
 952                MoveLR(1),
 953                MoveUD(-0.0509659),
 954                DelayOld(20),
 955                MoveUD(-0.247047),
 956                DelayOld(20),
 957                MoveUD(-0.443129),
 958                DelayOld(20),
 959                MoveUD(-0.694113),
 960                MoveUD(-0.921567),
 961                DelayOld(30),
 962                MoveLR(0.858821),
 963                MoveUD(-1),
 964                DelayOld(10),
 965                MoveLR(0.68627),
 966                DelayOld(10),
 967                MoveLR(0.364696),
 968                DelayOld(20),
 969                MoveLR(0.0509659),
 970                DelayOld(20),
 971                MoveLR(-0.223548),
 972                DelayOld(10),
 973                MoveLR(-0.600024),
 974                MoveUD(-0.913724),
 975                DelayOld(30),
 976                MoveLR(-0.858852),
 977                MoveUD(-0.717643),
 978                MoveLR(-1),
 979                MoveUD(-0.474502),
 980                DelayOld(20),
 981                MoveUD(-0.396069),
 982                DelayOld(20),
 983                MoveUD(-0.286264),
 984                DelayOld(20),
 985                MoveUD(-0.137242),
 986                DelayOld(20),
 987                MoveUD(0.0353099),
 988                DelayOld(10),
 989                MoveUD(0.32551),
 990                DelayOld(20),
 991                MoveUD(0.592181),
 992                DelayOld(10),
 993                MoveUD(0.851009),
 994                DelayOld(10),
 995                MoveUD(1),
 996                DelayOld(30),
 997                MoveLR(-0.764733),
 998                DelayOld(20),
 999                MoveLR(-0.403943),
1000                MoveLR(-0.145116),
1001                DelayOld(30),
1002                MoveLR(0.0901822),
1003                MoveLR(0.32548),
1004                DelayOld(30),
1005                MoveLR(0.560778),
1006                MoveUD(0.929441),
1007                DelayOld(20),
1008                MoveLR(0.709799),
1009                MoveUD(0.73336),
1010                MoveLR(0.803919),
1011                MoveUD(0.545122),
1012                DelayOld(20),
1013                MoveLR(0.882351),
1014                MoveUD(0.356883),
1015                DelayOld(10),
1016                MoveLR(0.968627),
1017                MoveUD(0.113742),
1018                DelayOld(20),
1019                MoveLR(0.992157),
1020                MoveUD(-0.0823389),
1021                DelayOld(30),
1022                MoveUD(-0.309793),
1023                DelayOld(10),
1024                MoveUD(-0.545091),
1025                DelayOld(20),
1026                MoveLR(0.882351),
1027                MoveUD(-0.874508),
1028                DelayOld(20),
1029                MoveLR(0.756859),
1030                MoveUD(-1),
1031                DelayOld(10),
1032                MoveLR(0.576464),
1033                DelayOld(20),
1034                MoveLR(0.254891),
1035                DelayOld(10),
1036                MoveLR(-0.0274667),
1037                DelayOld(10),
1038                MoveLR(-0.356883),
1039                DelayOld(30),
1040                MoveLR(-0.592181),
1041                MoveLR(-0.827479),
1042                MoveUD(-0.921567),
1043                DelayOld(20),
1044                MoveLR(-1),
1045                MoveUD(-0.749016),
1046                DelayOld(20),
1047                MoveUD(-0.61568),
1048                DelayOld(10),
1049                MoveUD(-0.403912),
1050                DelayOld(20),
1051                MoveUD(-0.207831),
1052                DelayOld(10),
1053                MoveUD(0.121586),
1054                DelayOld(30),
1055                MoveUD(0.34904),
1056                DelayOld(10),
1057                MoveUD(0.560808),
1058                DelayOld(10),
1059                MoveUD(0.827479),
1060                DelayOld(30),
1061                MoveUD(1),
1062                DelayOld(20),
1063                MoveLR(-0.976501),
1064                MoveLR(-0.670614),
1065                DelayOld(20),
1066                MoveLR(-0.239235),
1067                DelayOld(20),
1068                MoveLR(0.160772),
1069                DelayOld(20),
1070                MoveLR(0.443129),
1071                DelayOld(10),
1072                MoveLR(0.68627),
1073                MoveUD(0.976501),
1074                DelayOld(30),
1075                MoveLR(0.929411),
1076                MoveUD(0.73336),
1077                MoveLR(1),
1078                MoveUD(0.482376),
1079                DelayOld(20),
1080                MoveUD(0.34904),
1081                DelayOld(10),
1082                MoveUD(0.160802),
1083                DelayOld(30),
1084                MoveUD(-0.0744957),
1085                DelayOld(10),
1086                MoveUD(-0.333323),
1087                DelayOld(20),
1088                MoveUD(-0.647053),
1089                DelayOld(20),
1090                MoveUD(-0.937254),
1091                DelayOld(10),
1092                MoveLR(0.858821),
1093                MoveUD(-1),
1094                DelayOld(10),
1095                MoveLR(0.576464),
1096                DelayOld(30),
1097                MoveLR(0.184301),
1098                DelayOld(10),
1099                MoveLR(-0.121586),
1100                DelayOld(10),
1101                MoveLR(-0.474532),
1102                DelayOld(30),
1103                MoveLR(-0.670614),
1104                MoveLR(-0.851009),
1105                DelayOld(30),
1106                MoveLR(-1),
1107                MoveUD(-0.968627),
1108                DelayOld(20),
1109                MoveUD(-0.843135),
1110                DelayOld(10),
1111                MoveUD(-0.631367),
1112                DelayOld(20),
1113                MoveUD(-0.403912),
1114                MoveUD(-0.176458),
1115                DelayOld(20),
1116                MoveUD(0.0902127),
1117                DelayOld(20),
1118                MoveUD(0.380413),
1119                DelayOld(10),
1120                MoveUD(0.717673),
1121                DelayOld(30),
1122                MoveUD(1),
1123                DelayOld(10),
1124                MoveLR(-0.741203),
1125                DelayOld(20),
1126                MoveLR(-0.458846),
1127                DelayOld(10),
1128                MoveLR(-0.145116),
1129                DelayOld(10),
1130                MoveLR(0.0980255),
1131                DelayOld(20),
1132                MoveLR(0.294107),
1133                DelayOld(30),
1134                MoveLR(0.466659),
1135                MoveLR(0.717643),
1136                MoveUD(0.796106),
1137                DelayOld(20),
1138                MoveLR(0.921567),
1139                MoveUD(0.443159),
1140                DelayOld(20),
1141                MoveLR(1),
1142                MoveUD(0.145116),
1143                DelayOld(10),
1144                MoveUD(-0.0274361),
1145                DelayOld(30),
1146                MoveUD(-0.223518),
1147                MoveUD(-0.427442),
1148                DelayOld(20),
1149                MoveUD(-0.874508),
1150                DelayOld(20),
1151                MoveUD(-1),
1152                DelayOld(10),
1153                MoveLR(0.929411),
1154                DelayOld(20),
1155                MoveLR(0.68627),
1156                DelayOld(20),
1157                MoveLR(0.364696),
1158                DelayOld(20),
1159                MoveLR(0.0431227),
1160                DelayOld(10),
1161                MoveLR(-0.333354),
1162                DelayOld(20),
1163                MoveLR(-0.639241),
1164                DelayOld(20),
1165                MoveLR(-0.968657),
1166                MoveUD(-0.968627),
1167                DelayOld(20),
1168                MoveLR(-1),
1169                MoveUD(-0.890194),
1170                MoveUD(-0.866665),
1171                DelayOld(20),
1172                MoveUD(-0.749016),
1173                DelayOld(20),
1174                MoveUD(-0.529405),
1175                DelayOld(20),
1176                MoveUD(-0.30195),
1177                DelayOld(10),
1178                MoveUD(-0.00390637),
1179                DelayOld(10),
1180                MoveUD(0.262764),
1181                DelayOld(30),
1182                MoveLR(-0.600024),
1183                MoveUD(0.458846),
1184                DelayOld(10),
1185                MoveLR(-0.294137),
1186                MoveUD(0.482376),
1187                DelayOld(20),
1188                MoveLR(-0.200018),
1189                MoveUD(0.505905),
1190                DelayOld(10),
1191                MoveLR(-0.145116),
1192                MoveUD(0.545122),
1193                DelayOld(20),
1194                MoveLR(-0.0353099),
1195                MoveUD(0.584338),
1196                DelayOld(20),
1197                MoveLR(0.137242),
1198                MoveUD(0.592181),
1199                DelayOld(20),
1200                MoveLR(0.30195),
1201                DelayOld(10),
1202                MoveLR(0.490188),
1203                DelayOld(10),
1204                MoveLR(0.599994),
1205                MoveUD(0.529435),
1206                DelayOld(30),
1207                MoveLR(0.66274),
1208                MoveUD(0.3961),
1209                DelayOld(20),
1210                MoveLR(0.670583),
1211                MoveUD(0.231391),
1212                MoveLR(0.68627),
1213                MoveUD(0.0745262),
1214                Move(0, -0.01),
1215                DelayOld(100),
1216                Move(0, 0),
1217                DelayOld(1000),
1218                Text(ba.Lstr(resource=self._r +
1219                             '.phrase05Text')),  # for example when you punch..
1220                DelayOld(510),
1221                Move(0, -0.01),
1222                DelayOld(100),
1223                Move(0, 0),
1224                DelayOld(500),
1225                SpawnSpaz(0, (-0.09249162673950195, 4.337906360626221, -2.3),
1226                          make_current=True,
1227                          flash=False),
1228                SpawnSpaz(1, (-3.1, 4.3, -2.0),
1229                          make_current=False,
1230                          color=(1, 1, 0.4),
1231                          name=ba.Lstr(resource=self._r + '.randomName1Text')),
1232                Move(-1.0, 0),
1233                DelayOld(1050),
1234                Move(0, -0.01),
1235                DelayOld(100),
1236                Move(0, 0),
1237                DelayOld(1000),
1238                Text(ba.Lstr(resource=self._r +
1239                             '.phrase06Text')),  # your damage is based
1240                DelayOld(1200),
1241                Move(-0.05, 0),
1242                DelayOld(200),
1243                Punch(),
1244                DelayOld(800),
1245                Punch(),
1246                DelayOld(800),
1247                Punch(),
1248                DelayOld(800),
1249                Move(0, -0.01),
1250                DelayOld(100),
1251                Move(0, 0),
1252                Text(
1253                    ba.Lstr(resource=self._r + '.phrase07Text',
1254                            subs=[('${NAME}',
1255                                   ba.Lstr(resource=self._r +
1256                                           '.randomName1Text'))
1257                                  ])),  # see that didn't hurt fred
1258                DelayOld(2000),
1259                Celebrate('right', spaz_num=1),
1260                DelayOld(1400),
1261                Text(ba.Lstr(
1262                    resource=self._r +
1263                    '.phrase08Text')),  # lets jump and spin to get more speed
1264                DelayOld(30),
1265                MoveLR(0),
1266                DelayOld(40),
1267                MoveLR(0),
1268                DelayOld(40),
1269                MoveLR(0),
1270                DelayOld(130),
1271                MoveLR(0),
1272                DelayOld(100),
1273                MoveLR(0),
1274                DelayOld(10),
1275                MoveLR(0.0480667),
1276                DelayOld(40),
1277                MoveLR(0.056093),
1278                MoveLR(0.0681173),
1279                DelayOld(30),
1280                MoveLR(0.0801416),
1281                DelayOld(10),
1282                MoveLR(0.184301),
1283                DelayOld(10),
1284                MoveLR(0.207831),
1285                DelayOld(20),
1286                MoveLR(0.231361),
1287                DelayOld(30),
1288                MoveLR(0.239204),
1289                DelayOld(30),
1290                MoveLR(0.254891),
1291                DelayOld(40),
1292                MoveLR(0.270577),
1293                DelayOld(10),
1294                MoveLR(0.30195),
1295                DelayOld(20),
1296                MoveLR(0.341166),
1297                DelayOld(30),
1298                MoveLR(0.388226),
1299                MoveLR(0.435286),
1300                DelayOld(30),
1301                MoveLR(0.490188),
1302                DelayOld(10),
1303                MoveLR(0.560778),
1304                DelayOld(20),
1305                MoveLR(0.599994),
1306                DelayOld(10),
1307                MoveLR(0.647053),
1308                DelayOld(10),
1309                MoveLR(0.68627),
1310                DelayOld(30),
1311                MoveLR(0.733329),
1312                DelayOld(20),
1313                MoveLR(0.764702),
1314                DelayOld(10),
1315                MoveLR(0.827448),
1316                DelayOld(20),
1317                MoveLR(0.874508),
1318                DelayOld(20),
1319                MoveLR(0.929411),
1320                DelayOld(10),
1321                MoveLR(1),
1322                DelayOld(830),
1323                MoveUD(0.0274667),
1324                DelayOld(10),
1325                MoveLR(0.95294),
1326                MoveUD(0.113742),
1327                DelayOld(30),
1328                MoveLR(0.780389),
1329                MoveUD(0.184332),
1330                DelayOld(10),
1331                MoveLR(0.27842),
1332                MoveUD(0.0745262),
1333                DelayOld(20),
1334                MoveLR(0),
1335                MoveUD(0),
1336                DelayOld(390),
1337                MoveLR(0),
1338                MoveLR(0),
1339                DelayOld(20),
1340                MoveLR(0),
1341                DelayOld(20),
1342                MoveLR(0),
1343                DelayOld(10),
1344                MoveLR(-0.0537431),
1345                DelayOld(20),
1346                MoveLR(-0.215705),
1347                DelayOld(30),
1348                MoveLR(-0.388256),
1349                MoveLR(-0.529435),
1350                DelayOld(30),
1351                MoveLR(-0.694143),
1352                DelayOld(20),
1353                MoveLR(-0.851009),
1354                MoveUD(0.0588397),
1355                DelayOld(10),
1356                MoveLR(-1),
1357                MoveUD(0.0745262),
1358                Run(release=False),
1359                DelayOld(200),
1360                MoveUD(0.0509964),
1361                DelayOld(30),
1362                MoveUD(0.0117801),
1363                DelayOld(20),
1364                MoveUD(-0.0901822),
1365                MoveUD(-0.372539),
1366                DelayOld(30),
1367                MoveLR(-0.898068),
1368                MoveUD(-0.890194),
1369                Jump(release=False),
1370                DelayOld(20),
1371                MoveLR(-0.647084),
1372                MoveUD(-1),
1373                MoveLR(-0.427473),
1374                DelayOld(20),
1375                MoveLR(-0.00393689),
1376                DelayOld(10),
1377                MoveLR(0.537248),
1378                DelayOld(30),
1379                MoveLR(1),
1380                DelayOld(50),
1381                RunRelease(),
1382                JumpRelease(),
1383                DelayOld(50),
1384                MoveUD(-0.921567),
1385                MoveUD(-0.749016),
1386                DelayOld(30),
1387                MoveUD(-0.552934),
1388                DelayOld(10),
1389                MoveUD(-0.247047),
1390                DelayOld(20),
1391                MoveUD(0.200018),
1392                DelayOld(20),
1393                MoveUD(0.670614),
1394                MoveUD(1),
1395                DelayOld(70),
1396                MoveLR(0.97647),
1397                DelayOld(20),
1398                MoveLR(0.764702),
1399                DelayOld(20),
1400                MoveLR(0.364696),
1401                DelayOld(20),
1402                MoveLR(0.00390637),
1403                MoveLR(-0.309824),
1404                DelayOld(20),
1405                MoveLR(-0.576495),
1406                DelayOld(30),
1407                MoveLR(-0.898068),
1408                DelayOld(10),
1409                MoveLR(-1),
1410                MoveUD(0.905911),
1411                DelayOld(20),
1412                MoveUD(0.498062),
1413                DelayOld(20),
1414                MoveUD(0.0274667),
1415                MoveUD(-0.403912),
1416                DelayOld(20),
1417                MoveUD(-1),
1418                Run(release=False),
1419                Jump(release=False),
1420                DelayOld(10),
1421                Punch(release=False),
1422                DelayOld(70),
1423                JumpRelease(),
1424                DelayOld(110),
1425                MoveLR(-0.976501),
1426                RunRelease(),
1427                PunchRelease(),
1428                DelayOld(10),
1429                MoveLR(-0.952971),
1430                DelayOld(20),
1431                MoveLR(-0.905911),
1432                MoveLR(-0.827479),
1433                DelayOld(20),
1434                MoveLR(-0.75689),
1435                DelayOld(30),
1436                MoveLR(-0.73336),
1437                MoveLR(-0.694143),
1438                DelayOld(20),
1439                MoveLR(-0.670614),
1440                DelayOld(30),
1441                MoveLR(-0.66277),
1442                DelayOld(10),
1443                MoveUD(-0.960784),
1444                DelayOld(20),
1445                MoveLR(-0.623554),
1446                MoveUD(-0.874508),
1447                DelayOld(10),
1448                MoveLR(-0.545122),
1449                MoveUD(-0.694113),
1450                DelayOld(20),
1451                MoveLR(-0.505905),
1452                MoveUD(-0.474502),
1453                DelayOld(20),
1454                MoveLR(-0.458846),
1455                MoveUD(-0.356853),
1456                MoveLR(-0.364727),
1457                MoveUD(-0.27842),
1458                DelayOld(20),
1459                MoveLR(0.00390637),
1460                Move(0, 0),
1461                DelayOld(1000),
1462                Text(ba.Lstr(resource=self._r +
1463                             '.phrase09Text')),  # ah that's better
1464                DelayOld(1900),
1465                AnalyticsScreen('Tutorial Section 3'),
1466                Text(ba.Lstr(resource=self._r +
1467                             '.phrase10Text')),  # running also helps
1468                DelayOld(100),
1469                SpawnSpaz(0, (-3.2, 4.3, -4.4), make_current=True,
1470                          flash=False),
1471                SpawnSpaz(1, (3.3, 4.2, -5.8),
1472                          make_current=False,
1473                          color=(0.9, 0.5, 1.0),
1474                          name=ba.Lstr(resource=self._r + '.randomName2Text')),
1475                DelayOld(1800),
1476                Text(ba.Lstr(resource=self._r +
1477                             '.phrase11Text')),  # hold ANY button to run
1478                DelayOld(300),
1479                MoveUD(0),
1480                DelayOld(20),
1481                MoveUD(-0.0520646),
1482                DelayOld(20),
1483                MoveLR(0),
1484                MoveUD(-0.223518),
1485                Run(release=False),
1486                Jump(release=False),
1487                DelayOld(10),
1488                MoveLR(0.0980255),
1489                MoveUD(-0.309793),
1490                DelayOld(30),
1491                MoveLR(0.160772),
1492                MoveUD(-0.427442),
1493                DelayOld(20),
1494                MoveLR(0.231361),
1495                MoveUD(-0.545091),
1496                DelayOld(10),
1497                MoveLR(0.317637),
1498                MoveUD(-0.678426),
1499                DelayOld(20),
1500                MoveLR(0.396069),
1501                MoveUD(-0.819605),
1502                MoveLR(0.482345),
1503                MoveUD(-0.913724),
1504                DelayOld(20),
1505                MoveLR(0.560778),
1506                MoveUD(-1),
1507                DelayOld(20),
1508                MoveLR(0.607837),
1509                DelayOld(10),
1510                MoveLR(0.623524),
1511                DelayOld(30),
1512                MoveLR(0.647053),
1513                DelayOld(20),
1514                MoveLR(0.670583),
1515                MoveLR(0.694113),
1516                DelayOld(30),
1517                MoveLR(0.733329),
1518                DelayOld(20),
1519                MoveLR(0.764702),
1520                MoveLR(0.788232),
1521                DelayOld(20),
1522                MoveLR(0.827448),
1523                DelayOld(10),
1524                MoveLR(0.858821),
1525                DelayOld(20),
1526                MoveLR(0.921567),
1527                DelayOld(30),
1528                MoveLR(0.97647),
1529                MoveLR(1),
1530                DelayOld(130),
1531                MoveUD(-0.960784),
1532                DelayOld(20),
1533                MoveUD(-0.921567),
1534                DelayOld(30),
1535                MoveUD(-0.866665),
1536                MoveUD(-0.819605),
1537                DelayOld(30),
1538                MoveUD(-0.772546),
1539                MoveUD(-0.725486),
1540                DelayOld(30),
1541                MoveUD(-0.631367),
1542                DelayOld(10),
1543                MoveUD(-0.552934),
1544                DelayOld(20),
1545                MoveUD(-0.474502),
1546                DelayOld(10),
1547                MoveUD(-0.403912),
1548                DelayOld(30),
1549                MoveUD(-0.356853),
1550                DelayOld(30),
1551                MoveUD(-0.34901),
1552                DelayOld(20),
1553                MoveUD(-0.333323),
1554                DelayOld(20),
1555                MoveUD(-0.32548),
1556                DelayOld(10),
1557                MoveUD(-0.30195),
1558                DelayOld(20),
1559                MoveUD(-0.27842),
1560                DelayOld(30),
1561                MoveUD(-0.254891),
1562                MoveUD(-0.231361),
1563                DelayOld(30),
1564                MoveUD(-0.207831),
1565                DelayOld(20),
1566                MoveUD(-0.199988),
1567                MoveUD(-0.176458),
1568                DelayOld(30),
1569                MoveUD(-0.137242),
1570                MoveUD(-0.0823389),
1571                DelayOld(20),
1572                MoveUD(-0.0274361),
1573                DelayOld(20),
1574                MoveUD(0.00393689),
1575                DelayOld(40),
1576                MoveUD(0.0353099),
1577                DelayOld(20),
1578                MoveUD(0.113742),
1579                DelayOld(10),
1580                MoveUD(0.137272),
1581                DelayOld(20),
1582                MoveUD(0.160802),
1583                MoveUD(0.184332),
1584                DelayOld(20),
1585                MoveUD(0.207862),
1586                DelayOld(30),
1587                MoveUD(0.247078),
1588                MoveUD(0.262764),
1589                DelayOld(20),
1590                MoveUD(0.270608),
1591                DelayOld(30),
1592                MoveUD(0.294137),
1593                MoveUD(0.32551),
1594                DelayOld(30),
1595                MoveUD(0.37257),
1596                Celebrate('left', 1),
1597                DelayOld(20),
1598                MoveUD(0.498062),
1599                MoveUD(0.560808),
1600                DelayOld(30),
1601                MoveUD(0.654927),
1602                MoveUD(0.694143),
1603                DelayOld(30),
1604                MoveUD(0.741203),
1605                DelayOld(20),
1606