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

Our player type for this game.

pressed
Inherited Members
bascenev1._player.Player
character
actor
color
highlight
on_expire
team
customdata
sessionplayer
node
position
exists
getname
is_alive
get_icon
assigninput
resetinput
class Team(bascenev1._team.Team[bascenev1lib.tutorial.Player]):
181class Team(bs.Team[Player]):
182    """Our team type for this game."""
183
184    def __init__(self) -> None:
185        pass

Our team type for this game.

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

Units of execution wrangled by a bascenev1.Session.

Category: Gameplay Classes

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

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

Creates an Activity in the current bascenev1.Session.

The activity will not be actually run until bascenev1.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.

current_spaz: bascenev1lib.actor.spaz.Spaz | None
last_start_time: int | None
cycle_times: list[int]
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).

spawn_sound
map: bascenev1.Map | None
text: _bascenev1.Node | None
punch_image_color
punch_image: _bascenev1.Node | None
bomb_image: _bascenev1.Node | None
jump_image: _bascenev1.Node | None
pickup_image: _bascenev1.Node | None
bomb_image_color
pickup_image_color
control_ui_nodes: list[_bascenev1.Node]
spazzes: dict[int, bascenev1lib.actor.spaz.Spaz]
jump_image_color
@override
def on_transition_in(self) -> None:
238    @override
239    def on_transition_in(self) -> None:
240        super().on_transition_in()
241        bs.setmusic(bs.MusicType.CHAR_SELECT, continuous=True)
242        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 bascenev1.Activity.on_begin() is called.

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

Called once the previous 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:
416    def set_stick_image_position(self, x: float, y: float) -> None:
417        # Clamp this to a circle.
418        len_squared = x * x + y * y
419        if len_squared > 1.0:
420            length = math.sqrt(len_squared)
421            mult = 1.0 / length
422            x *= mult
423            y *= mult
424
425        self.stick_image_position_x = x
426        self.stick_image_position_y = y
427        offs = 50.0
428        assert self._scale is not None
429        p = [
430            self._stick_nub_position[0] + x * offs * self._scale,
431            self._stick_nub_position[1] + y * offs * self._scale,
432        ]
433        c = list(self._stick_nub_image_color)
434        if abs(x) > 0.1 or abs(y) > 0.1:
435            c[0] *= 2.0
436            c[1] *= 4.0
437            c[2] *= 2.0
438        assert self._stick_nub_image is not None
439        self._stick_nub_image.position = p
440        self._stick_nub_image.color = c
441        c = list(self._stick_base_image_color)
442        if abs(x) > 0.1 or abs(y) > 0.1:
443            c[0] *= 1.5
444            c[1] *= 1.5
445            c[2] *= 1.5
446        assert self._stick_base_image is not None
447        self._stick_base_image.color = c
@override
def on_player_join(self, player: Player) -> None:
2519    @override
2520    def on_player_join(self, player: Player) -> None:
2521        super().on_player_join(player)
2522
2523        # We just wanna know if this player presses anything.
2524        player.assigninput(
2525            (
2526                bs.InputType.JUMP_PRESS,
2527                bs.InputType.PUNCH_PRESS,
2528                bs.InputType.BOMB_PRESS,
2529                bs.InputType.PICK_UP_PRESS,
2530            ),
2531            bs.Call(self._player_pressed_button, player),
2532        )

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

(including the initial set of Players)

@override
def on_player_leave(self, player: Player) -> None:
2534    @override
2535    def on_player_leave(self, player: Player) -> None:
2536        if not all(self.players):
2537            logging.error(
2538                'Nonexistent player in on_player_leave: %s: we are %s',
2539                [str(p) for p in self.players],
2540                player,
2541            )
2542        super().on_player_leave(player)
2543        # our leaving may influence the vote total needed/etc
2544        self._update_skip_votes()

Called when a bascenev1.Player is leaving the Activity.

Inherited Members
bascenev1._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
paused_text
preloads
lobby
context
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
bascenev1._dependency.DependencyComponent
dep_is_present
get_dynamic_deps