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