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

Our player type for this game.

Player()
183    def __init__(self) -> None:
184        self.pressed = False
Inherited Members
ba._player.Player
actor
on_expire
team
customdata
sessionplayer
node
position
exists
getname
is_alive
get_icon
assigninput
resetinput
class Team(ba._team.Team[bastd.tutorial.Player]):
187class Team(ba.Team[Player]):
188    """Our team type for this game."""
189
190    def __init__(self) -> None:
191        pass

Our team type for this game.

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

Units of execution wrangled by a ba.Session.

Category: Gameplay Classes

Examples of Activities include games, score-screens, cutscenes, etc. A ba.Session has one 'current' Activity at any time, though their existence can overlap during transitions.

TutorialActivity(settings: dict | None = None)
195    def __init__(self, settings: dict | None = None):
196        from bastd.maps import Rampage
197
198        if settings is None:
199            settings = {}
200        super().__init__(settings)
201        self.current_spaz: basespaz.Spaz | None = None
202        self._benchmark_type = getattr(ba.getsession(), 'benchmark_type', None)
203        self.last_start_time: int | None = None
204        self.cycle_times: list[int] = []
205        self.allow_pausing = True
206        self.allow_kick_idle_players = False
207        self._issued_warning = False
208        self._map_type = Rampage
209        self._map_type.preload()
210        self._jump_button_tex = ba.gettexture('buttonJump')
211        self._pick_up_button_tex = ba.gettexture('buttonPickUp')
212        self._bomb_button_tex = ba.gettexture('buttonBomb')
213        self._punch_button_tex = ba.gettexture('buttonPunch')
214        self._r = 'tutorial'
215        self._have_skipped = False
216        self.stick_image_position_x = self.stick_image_position_y = 0.0
217        self.spawn_sound = ba.getsound('spawn')
218        self.map: ba.Map | None = None
219        self.text: ba.Node | None = None
220        self._skip_text: ba.Node | None = None
221        self._skip_count_text: ba.Node | None = None
222        self._scale: float | None = None
223        self._stick_base_position: tuple[float, float] = (0.0, 0.0)
224        self._stick_nub_position: tuple[float, float] = (0.0, 0.0)
225        self._stick_base_image_color: Sequence[float] = (1.0, 1.0, 1.0, 1.0)
226        self._stick_nub_image_color: Sequence[float] = (1.0, 1.0, 1.0, 1.0)
227        self._time: int = -1
228        self.punch_image_color = (1.0, 1.0, 1.0)
229        self.punch_image: ba.Node | None = None
230        self.bomb_image: ba.Node | None = None
231        self.jump_image: ba.Node | None = None
232        self.pickup_image: ba.Node | None = None
233        self._stick_base_image: ba.Node | None = None
234        self._stick_nub_image: ba.Node | None = None
235        self.bomb_image_color = (1.0, 1.0, 1.0)
236        self.pickup_image_color = (1.0, 1.0, 1.0)
237        self.control_ui_nodes: list[ba.Node] = []
238        self.spazzes: dict[int, basespaz.Spaz] = {}
239        self.jump_image_color = (1.0, 1.0, 1.0)
240        self._entries: deque[Any] = deque()
241        self._read_entries_timer: ba.Timer | None = None
242        self._entry_timer: ba.Timer | None = None

Creates an Activity in the current ba.Session.

The activity will not be actually run until ba.Session.setactivity is called. 'settings' should be a dict of key/value pairs specific to the activity.

Activities should preload as much of their media/etc as possible in their constructor, but none of it should actually be used until they are transitioned in.

allow_pausing = False

Whether game-time should still progress when in menus/etc.

allow_kick_idle_players = True

Whether idle players can potentially be kicked (should not happen in menus/etc).

def on_transition_in(self) -> None:
244    def on_transition_in(self) -> None:
245        super().on_transition_in()
246        ba.setmusic(ba.MusicType.CHAR_SELECT, continuous=True)
247        self.map = self._map_type()

Called when the Activity is first becoming visible.

Upon this call, the Activity should fade in backgrounds, start playing music, etc. It does not yet have access to players or teams, however. They remain owned by the previous Activity up until ba.Activity.on_begin() is called.

def on_begin(self) -> None:
249    def on_begin(self) -> None:
250        super().on_begin()
251
252        ba.set_analytics_screen('Tutorial Start')
253        ba.internal.increment_analytics_count('Tutorial start')
254
255        if bool(False):
256            # Buttons on top.
257            text_y = 140
258            buttons_y = 250
259        else:
260            # Buttons on bottom.
261            text_y = 260
262            buttons_y = 160
263
264        # Need different versions of this: taps/buttons/keys.
265        self.text = ba.newnode(
266            'text',
267            attrs={
268                'text': '',
269                'scale': 1.9,
270                'position': (0, text_y),
271                'maxwidth': 500,
272                'flatness': 0.0,
273                'shadow': 0.5,
274                'h_align': 'center',
275                'v_align': 'center',
276                'v_attach': 'center',
277            },
278        )
279
280        # Need different versions of this: taps/buttons/keys.
281        txt = (
282            ba.Lstr(resource=self._r + '.cpuBenchmarkText')
283            if self._benchmark_type == 'cpu'
284            else ba.Lstr(resource=self._r + '.toSkipPressAnythingText')
285        )
286        t = self._skip_text = ba.newnode(
287            'text',
288            attrs={
289                'text': txt,
290                'maxwidth': 900,
291                'scale': 1.1,
292                'vr_depth': 100,
293                'position': (0, 30),
294                'h_align': 'center',
295                'v_align': 'center',
296                'v_attach': 'bottom',
297            },
298        )
299        ba.animate(t, 'opacity', {1.0: 0.0, 2.0: 0.7})
300        self._skip_count_text = ba.newnode(
301            'text',
302            attrs={
303                'text': '',
304                'scale': 1.4,
305                'vr_depth': 90,
306                'position': (0, 70),
307                'h_align': 'center',
308                'v_align': 'center',
309                'v_attach': 'bottom',
310            },
311        )
312
313        ouya = False
314
315        self._scale = scale = 0.6
316        center_offs = 130.0 * scale
317        offs = 65.0 * scale
318        position = (0, buttons_y)
319        image_size = 90.0 * scale
320        image_size_2 = 220.0 * scale
321        nub_size = 110.0 * scale
322        p = (position[0] + center_offs, position[1] - offs)
323
324        def _sc(r: float, g: float, b: float) -> tuple[float, float, float]:
325            return 0.6 * r, 0.6 * g, 0.6 * b
326
327        self.jump_image_color = c = _sc(0.4, 1, 0.4)
328        self.jump_image = ba.newnode(
329            'image',
330            attrs={
331                'texture': self._jump_button_tex,
332                'absolute_scale': True,
333                'vr_depth': -20,
334                'position': p,
335                'scale': (image_size, image_size),
336                'color': c,
337            },
338        )
339        p = (position[0] + center_offs - offs, position[1])
340        self.punch_image_color = c = (
341            _sc(0.2, 0.6, 1) if ouya else _sc(1, 0.7, 0.3)
342        )
343        self.punch_image = ba.newnode(
344            'image',
345            attrs={
346                'texture': ba.gettexture('buttonPunch'),
347                'absolute_scale': True,
348                'vr_depth': -20,
349                'position': p,
350                'scale': (image_size, image_size),
351                'color': c,
352            },
353        )
354        p = (position[0] + center_offs + offs, position[1])
355        self.bomb_image_color = c = _sc(1, 0.3, 0.3)
356        self.bomb_image = ba.newnode(
357            'image',
358            attrs={
359                'texture': ba.gettexture('buttonBomb'),
360                'absolute_scale': True,
361                'vr_depth': -20,
362                'position': p,
363                'scale': (image_size, image_size),
364                'color': c,
365            },
366        )
367        p = (position[0] + center_offs, position[1] + offs)
368        self.pickup_image_color = c = (
369            _sc(1, 0.8, 0.3) if ouya else _sc(0.5, 0.5, 1)
370        )
371        self.pickup_image = ba.newnode(
372            'image',
373            attrs={
374                'texture': ba.gettexture('buttonPickUp'),
375                'absolute_scale': True,
376                'vr_depth': -20,
377                'position': p,
378                'scale': (image_size, image_size),
379                'color': c,
380            },
381        )
382
383        self._stick_base_position = p = (position[0] - center_offs, position[1])
384        self._stick_base_image_color = c2 = (0.25, 0.25, 0.25, 1.0)
385        self._stick_base_image = ba.newnode(
386            'image',
387            attrs={
388                'texture': ba.gettexture('nub'),
389                'absolute_scale': True,
390                'vr_depth': -40,
391                'position': p,
392                'scale': (image_size_2, image_size_2),
393                'color': c2,
394            },
395        )
396        self._stick_nub_position = p = (position[0] - center_offs, position[1])
397        self._stick_nub_image_color = c3 = (0.4, 0.4, 0.4, 1.0)
398        self._stick_nub_image = ba.newnode(
399            'image',
400            attrs={
401                'texture': ba.gettexture('nub'),
402                'absolute_scale': True,
403                'position': p,
404                'scale': (nub_size, nub_size),
405                'color': c3,
406            },
407        )
408        self.control_ui_nodes = [
409            self.jump_image,
410            self.punch_image,
411            self.bomb_image,
412            self.pickup_image,
413            self._stick_base_image,
414            self._stick_nub_image,
415        ]
416        for n in self.control_ui_nodes:
417            n.opacity = 0.0
418        self._read_entries()

Called once the previous ba.Activity has finished transitioning out.

At this point the activity's initial players and teams are filled in and it should begin its actual game logic.

def set_stick_image_position(self, x: float, y: float) -> None:
420    def set_stick_image_position(self, x: float, y: float) -> None:
421
422        # Clamp this to a circle.
423        len_squared = x * x + y * y
424        if len_squared > 1.0:
425            length = math.sqrt(len_squared)
426            mult = 1.0 / length
427            x *= mult
428            y *= mult
429
430        self.stick_image_position_x = x
431        self.stick_image_position_y = y
432        offs = 50.0
433        assert self._scale is not None
434        p = [
435            self._stick_nub_position[0] + x * offs * self._scale,
436            self._stick_nub_position[1] + y * offs * self._scale,
437        ]
438        c = list(self._stick_nub_image_color)
439        if abs(x) > 0.1 or abs(y) > 0.1:
440            c[0] *= 2.0
441            c[1] *= 4.0
442            c[2] *= 2.0
443        assert self._stick_nub_image is not None
444        self._stick_nub_image.position = p
445        self._stick_nub_image.color = c
446        c = list(self._stick_base_image_color)
447        if abs(x) > 0.1 or abs(y) > 0.1:
448            c[0] *= 1.5
449            c[1] *= 1.5
450            c[2] *= 1.5
451        assert self._stick_base_image is not None
452        self._stick_base_image.color = c
def on_player_join(self, player: bastd.tutorial.Player) -> None:
2537    def on_player_join(self, player: Player) -> None:
2538        super().on_player_join(player)
2539
2540        # We just wanna know if this player presses anything.
2541        player.assigninput(
2542            (
2543                ba.InputType.JUMP_PRESS,
2544                ba.InputType.PUNCH_PRESS,
2545                ba.InputType.BOMB_PRESS,
2546                ba.InputType.PICK_UP_PRESS,
2547            ),
2548            ba.Call(self._player_pressed_button, player),
2549        )

Called when a new ba.Player has joined the Activity.

(including the initial set of Players)

def on_player_leave(self, player: bastd.tutorial.Player) -> None:
2551    def on_player_leave(self, player: Player) -> None:
2552        if not all(self.players):
2553            ba.print_error(
2554                'Nonexistent player in on_player_leave: '
2555                + str([str(p) for p in self.players])
2556                + ': we are '
2557                + str(player)
2558            )
2559        super().on_player_leave(player)
2560        # our leaving may influence the vote total needed/etc
2561        self._update_skip_votes()

Called when a ba.Player is leaving the Activity.

Inherited Members
ba._activity.Activity
settings_raw
teams
players
announce_player_deaths
is_joining_activity
use_fixed_vr_overlay
slow_motion
inherits_slow_motion
inherits_music
inherits_vr_camera_offset
inherits_vr_overlay_center
inherits_tint
allow_mid_activity_joins
transition_time
can_show_ad_on_death
globalsnode
stats
on_expire
customdata
expired
playertype
teamtype
retain_actor
add_actor_weak_ref
session
on_team_join
on_team_leave
on_transition_out
handlemessage
has_transitioned_in
has_begun
has_ended
is_transitioning_out
transition_out
end
create_player
create_team
ba._dependency.DependencyComponent
dep_is_present
get_dynamic_deps