pxt-arcade 1.12.13 → 1.12.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -818,6 +818,11 @@ declare namespace pxsim {
818
818
  instruction: "playinstructions" | "muteallchannels";
819
819
  soundbuf?: Uint8Array;
820
820
  }
821
+ interface MultiplayerConnectionEvent extends SimulatorMultiplayerMessage {
822
+ content: "Connection";
823
+ slot: number;
824
+ connected: boolean;
825
+ }
821
826
  class MultiplayerState {
822
827
  lastMessageId: number;
823
828
  origin: string;
@@ -826,6 +831,7 @@ declare namespace pxsim {
826
831
  send(msg: SimulatorMultiplayerMessage): void;
827
832
  init(origin: string): void;
828
833
  setButton(key: number, isPressed: boolean): void;
834
+ registerConnectionState(player: number, connected: boolean): void;
829
835
  protected messageHandler(msg: SimulatorMessage): void;
830
836
  }
831
837
  }
@@ -2554,8 +2554,6 @@ var pxsim;
2554
2554
  }
2555
2555
  multiplayer.postImage = postImage;
2556
2556
  function postIcon(iconType, slot, im) {
2557
- if (pxsim.getMultiplayerState().origin !== "server")
2558
- return;
2559
2557
  if (im._width * im._height > 64 * 64) {
2560
2558
  // setting 64x64 as max size for icon for now
2561
2559
  return;
@@ -2596,6 +2594,8 @@ var pxsim;
2596
2594
  IconType[IconType["Player"] = 0] = "Player";
2597
2595
  IconType[IconType["Reaction"] = 1] = "Reaction";
2598
2596
  })(IconType = pxsim.IconType || (pxsim.IconType = {}));
2597
+ const MULTIPLAYER_PLAYER_JOINED_ID = 3241;
2598
+ const MULTIPLAYER_PLAYER_LEFT_ID = 3242;
2599
2599
  class MultiplayerState {
2600
2600
  constructor() {
2601
2601
  this.lastMessageId = 0;
@@ -2628,6 +2628,11 @@ var pxsim;
2628
2628
  });
2629
2629
  }
2630
2630
  }
2631
+ registerConnectionState(player, connected) {
2632
+ const evId = connected ? MULTIPLAYER_PLAYER_JOINED_ID : MULTIPLAYER_PLAYER_LEFT_ID;
2633
+ const b = pxsim.board();
2634
+ b.bus.queue(evId, player);
2635
+ }
2631
2636
  messageHandler(msg) {
2632
2637
  if (!isMultiplayerMessage(msg)) {
2633
2638
  return;
@@ -2661,6 +2666,11 @@ var pxsim;
2661
2666
  }
2662
2667
  }
2663
2668
  }
2669
+ else if (isConnectionMessage(msg)) {
2670
+ if (this.origin === "server") {
2671
+ this.registerConnectionState(msg.slot, msg.connected);
2672
+ }
2673
+ }
2664
2674
  }
2665
2675
  }
2666
2676
  pxsim.MultiplayerState = MultiplayerState;
@@ -2676,6 +2686,9 @@ var pxsim;
2676
2686
  function isAudioMessage(msg) {
2677
2687
  return msg && msg.content === "Audio";
2678
2688
  }
2689
+ function isConnectionMessage(msg) {
2690
+ return msg && msg.content === "Connection";
2691
+ }
2679
2692
  })(pxsim || (pxsim = {}));
2680
2693
  var pxsim;
2681
2694
  (function (pxsim) {
package/built/sim.js CHANGED
@@ -156,11 +156,17 @@ var pxsim;
156
156
  let isFirstRunSafari = true;
157
157
  window.addEventListener("DOMContentLoaded", () => {
158
158
  const searchParams = new URL(window.location.toString()).searchParams;
159
- setSimThemeColor("background-color", searchParams.get("background-color"));
160
- setSimThemeColor("button-stroke", searchParams.get("button-stroke"));
161
- setSimThemeColor("text-color", searchParams.get("text-color"));
162
- setSimThemeColor("button-fill", searchParams.get("button-fill"));
163
- setSimThemeColor("dpad-fill", searchParams.get("dpad-fill"));
159
+ const setThemeIfDefined = (themeType) => {
160
+ const paramVal = searchParams.get(themeType);
161
+ if (paramVal) {
162
+ setSimThemeColor(themeType, paramVal);
163
+ }
164
+ };
165
+ setThemeIfDefined("background-color");
166
+ setThemeIfDefined("button-stroke");
167
+ setThemeIfDefined("text-color");
168
+ setThemeIfDefined("button-fill");
169
+ setThemeIfDefined("dpad-fill");
164
170
  if (!!searchParams.get("pointer-events"))
165
171
  registerPointerEvents();
166
172
  if (!!searchParams.get("hideSimButtons"))
@@ -223,20 +229,33 @@ var pxsim;
223
229
  canvas.addEventListener("pointerout", reporter);
224
230
  canvas.addEventListener("wheel", wheelReporter);
225
231
  }
226
- function setSimThemeColor(part, color) {
227
- if (!part || !color || !/^[0-9A-F]{6}$/i.test(color))
232
+ function setSimThemeColor(part, color, elOverride) {
233
+ if (!part || (!(color == undefined || /^[0-9A-F]{6}$/i.test(color))))
228
234
  return;
235
+ if (part != "background-color"
236
+ && part != "button-stroke"
237
+ && part != "text-color"
238
+ && part != "button-fill"
239
+ && part != "dpad-fill") {
240
+ return;
241
+ }
229
242
  const propName = `--sim-${part}`;
230
- const propColor = `#${color}`;
231
- const wrapper = document.getElementById("wrap");
232
- wrapper.style.setProperty(propName, propColor);
243
+ const propColor = color ? `#${color}` : undefined;
244
+ const wrapper = elOverride || document.getElementById("wrap");
245
+ if (propColor) {
246
+ wrapper.style.setProperty(propName, propColor);
247
+ }
248
+ else {
249
+ wrapper.style.removeProperty(propName);
250
+ }
233
251
  }
234
252
  /**
235
253
  * This function gets called each time the program restarts
236
254
  */
237
- pxsim.initCurrentRuntime = () => {
255
+ pxsim.initCurrentRuntime = (msg) => {
238
256
  pxsim.runtime.board = new Board();
239
257
  pxsim.initGamepad();
258
+ board().setActivePlayer(msg.activePlayer);
240
259
  if (!forcedUpdateLoop) {
241
260
  forcedUpdateLoop = true;
242
261
  // this is used to force screen update if game loop is stuck or not set up properly
@@ -305,6 +324,7 @@ var pxsim;
305
324
  }
306
325
  };
307
326
  window.addEventListener("message", (ev) => {
327
+ var _a;
308
328
  if (ev.data.button !== undefined && ev.data.type !== "multiplayer") {
309
329
  let key;
310
330
  switch (ev.data.button) {
@@ -344,6 +364,15 @@ var pxsim;
344
364
  b.multiplayerState.origin = ev.data.context;
345
365
  }
346
366
  }
367
+ if (ev.data.type == "setactiveplayer") {
368
+ const b = board();
369
+ if (!(b.multiplayerState && b.multiplayerState.origin)) {
370
+ b.setActivePlayer(ev.data.playerNumber);
371
+ }
372
+ }
373
+ else if (ev.data.type == "setsimthemecolor") {
374
+ setSimThemeColor(ev.data.part, (_a = ev.data.color) === null || _a === void 0 ? void 0 : _a.replace("#", ""));
375
+ }
347
376
  });
348
377
  }
349
378
  };
@@ -425,6 +454,32 @@ var pxsim;
425
454
  const scale = isEdge() || isIE() ? 10 : 1;
426
455
  this.gameplayer = new pxsim.visuals.GamePlayer(scale);
427
456
  throttleAnimation((cb) => (this.screenState.onChange = cb), () => this.gameplayer.draw(this.screenState));
457
+ this.activePlayer = undefined;
458
+ }
459
+ setActivePlayer(playerNumber) {
460
+ if (this.multiplayerState && this.multiplayerState.origin)
461
+ return;
462
+ // TODO: this is duplicated in pxt/multiplayer's ArcadeSimulator.tsx;
463
+ // we could dedup this by starting a set of 'named' themes in the future
464
+ // (e.g. player1, player2, hotrodflames, ...)
465
+ // [[backgroundColor, buttonStroke]]
466
+ const playerThemes = [
467
+ [undefined, undefined],
468
+ ["ED3636", "8D2525"],
469
+ ["4E4EE9", "3333A1"],
470
+ ["FF9A14", "B0701A"],
471
+ ["4EB94E", "245D24"],
472
+ ];
473
+ const newPlayerTheme = playerThemes[playerNumber || 0];
474
+ if (!newPlayerTheme) {
475
+ // invalid playerNumber
476
+ return;
477
+ }
478
+ const themeOverrideElement = document.querySelector(".game-player");
479
+ setSimThemeColor("background-color", newPlayerTheme[0], themeOverrideElement);
480
+ setSimThemeColor("button-stroke", newPlayerTheme[1], themeOverrideElement);
481
+ setSimThemeColor("dpad-fill", newPlayerTheme[1], themeOverrideElement);
482
+ this.activePlayer = playerNumber || undefined;
428
483
  }
429
484
  getDefaultPitchPin() {
430
485
  return undefined;
@@ -438,14 +493,24 @@ var pxsim;
438
493
  }
439
494
  }
440
495
  setButton(which, isPressed) {
496
+ const inMultiplayerSession = !!this.multiplayerState.origin;
441
497
  // Disallow local input for player 2+ in multiplayer mode.
442
- if (this.multiplayerState.origin && which > pxsim.Key.Menu)
498
+ if (inMultiplayerSession && which > pxsim.Key.Menu)
443
499
  return;
444
- if (which) {
445
- this.handleKeyEvent(which, isPressed);
446
- }
447
- }
448
- handleKeyEvent(key, isPressed) {
500
+ if (!which)
501
+ return;
502
+ let playerOffset = 0;
503
+ if (!inMultiplayerSession
504
+ && this.activePlayer
505
+ && this.activePlayer > 1
506
+ && which > 0
507
+ && which < 7) {
508
+ playerOffset = this.activePlayer - 1;
509
+ }
510
+ this.handleKeyEvent(which, isPressed, playerOffset);
511
+ }
512
+ handleKeyEvent(key, isPressed, playerOffset = 0) {
513
+ const gameKey = key + 7 * (playerOffset | 0);
449
514
  // handle system keys
450
515
  switch (key) {
451
516
  case pxsim.Key.Reset:
@@ -475,10 +540,14 @@ var pxsim;
475
540
  break;
476
541
  }
477
542
  //this.lastKey = Date.now()
478
- this.bus.queue(isPressed ? INTERNAL_KEY_DOWN : INTERNAL_KEY_UP, key);
479
- this.bus.queue(isPressed ? INTERNAL_KEY_DOWN : INTERNAL_KEY_UP, 0); // "any" key
480
- if (this.gameplayer)
543
+ this.bus.queue(isPressed ? INTERNAL_KEY_DOWN : INTERNAL_KEY_UP, gameKey);
544
+ // no 'any' for p2-4
545
+ if (!playerOffset) {
546
+ this.bus.queue(isPressed ? INTERNAL_KEY_DOWN : INTERNAL_KEY_UP, 0); // "any" key
547
+ }
548
+ if (this.gameplayer) {
481
549
  this.gameplayer.buttonChanged(key, isPressed);
550
+ }
482
551
  if (this.multiplayerState && key >= pxsim.Key.Left && key <= pxsim.Key.B) {
483
552
  this.multiplayerState.setButton(key, isPressed);
484
553
  }
@@ -494,10 +563,10 @@ var pxsim;
494
563
  }
495
564
  resize() { }
496
565
  async initAsync(msg) {
497
- var _a;
498
566
  if (msg.options.mpRole) {
499
567
  this.multiplayerState.origin = msg.options.mpRole;
500
568
  }
569
+ this.setActivePlayer(msg.activePlayer);
501
570
  this.runOptions = msg;
502
571
  this.stats = document.getElementById("debug-stats");
503
572
  this.stats.className = "stats no-select";
@@ -518,7 +587,7 @@ var pxsim;
518
587
  let safariEnablePromise;
519
588
  if (isFirstRunSafari && !safariEnablePromise) {
520
589
  const safariWarning = document.getElementById("safari-enable-game");
521
- if (isSafari() && ((_a = msg.options) === null || _a === void 0 ? void 0 : _a.mpRole) === "server") {
590
+ if (isSafari() && msg.options && msg.options.mpRole === "server") {
522
591
  safariEnablePromise = new Promise(resolve => {
523
592
  safariWarning.style.display = "flex";
524
593
  safariWarning.addEventListener("click", () => {
@@ -1262,11 +1331,11 @@ var pxsim;
1262
1331
  var visuals;
1263
1332
  (function (visuals) {
1264
1333
  function pressButton(button) {
1265
- pxsim.board().handleKeyEvent(button, true);
1334
+ pxsim.board().setButton(button, true);
1266
1335
  }
1267
1336
  visuals.pressButton = pressButton;
1268
1337
  function releaseButton(button) {
1269
- pxsim.board().handleKeyEvent(button, false);
1338
+ pxsim.board().setButton(button, false);
1270
1339
  }
1271
1340
  visuals.releaseButton = releaseButton;
1272
1341
  function hasPointerEvents() {
@@ -2799,8 +2868,6 @@ var pxsim;
2799
2868
  }
2800
2869
  multiplayer.postImage = postImage;
2801
2870
  function postIcon(iconType, slot, im) {
2802
- if (pxsim.getMultiplayerState().origin !== "server")
2803
- return;
2804
2871
  if (im._width * im._height > 64 * 64) {
2805
2872
  // setting 64x64 as max size for icon for now
2806
2873
  return;
@@ -2841,6 +2908,8 @@ var pxsim;
2841
2908
  IconType[IconType["Player"] = 0] = "Player";
2842
2909
  IconType[IconType["Reaction"] = 1] = "Reaction";
2843
2910
  })(IconType = pxsim.IconType || (pxsim.IconType = {}));
2911
+ const MULTIPLAYER_PLAYER_JOINED_ID = 3241;
2912
+ const MULTIPLAYER_PLAYER_LEFT_ID = 3242;
2844
2913
  class MultiplayerState {
2845
2914
  constructor() {
2846
2915
  this.lastMessageId = 0;
@@ -2873,6 +2942,11 @@ var pxsim;
2873
2942
  });
2874
2943
  }
2875
2944
  }
2945
+ registerConnectionState(player, connected) {
2946
+ const evId = connected ? MULTIPLAYER_PLAYER_JOINED_ID : MULTIPLAYER_PLAYER_LEFT_ID;
2947
+ const b = pxsim.board();
2948
+ b.bus.queue(evId, player);
2949
+ }
2876
2950
  messageHandler(msg) {
2877
2951
  if (!isMultiplayerMessage(msg)) {
2878
2952
  return;
@@ -2906,6 +2980,11 @@ var pxsim;
2906
2980
  }
2907
2981
  }
2908
2982
  }
2983
+ else if (isConnectionMessage(msg)) {
2984
+ if (this.origin === "server") {
2985
+ this.registerConnectionState(msg.slot, msg.connected);
2986
+ }
2987
+ }
2909
2988
  }
2910
2989
  }
2911
2990
  pxsim.MultiplayerState = MultiplayerState;
@@ -2921,6 +3000,9 @@ var pxsim;
2921
3000
  function isAudioMessage(msg) {
2922
3001
  return msg && msg.content === "Audio";
2923
3002
  }
3003
+ function isConnectionMessage(msg) {
3004
+ return msg && msg.content === "Connection";
3005
+ }
2924
3006
  })(pxsim || (pxsim = {}));
2925
3007
  var pxsim;
2926
3008
  (function (pxsim) {
@@ -44,10 +44,10 @@
44
44
  "Microsoft MakeCode Arcade": "Microsoft MakeCode Arcade",
45
45
  "Mouse emulation over HID": "Mouse emulation over HID",
46
46
  "Multiplayer Games": "Multiplayer Games",
47
+ "Multiplayer Games!": "Multiplayer Games!",
47
48
  "NRF52833 board": "NRF52833 board",
48
49
  "NRF52840 board": "NRF52840 board",
49
50
  "Networking abstractions": "Networking abstractions",
50
- "New? Start here!": "New? Start here!",
51
51
  "Onboard light level sensor": "Onboard light level sensor",
52
52
  "Palette manipulations": "Palette manipulations",
53
53
  "Power and sleep management": "Power and sleep management",
@@ -60,7 +60,6 @@
60
60
  "Settings storage in internal flash": "Settings storage in internal flash",
61
61
  "Seven segment digit display": "Seven segment digit display",
62
62
  "Skillmaps": "Skillmaps",
63
- "Start Skillmap": "Start Skillmap",
64
63
  "The accelerometer library": "The accelerometer library",
65
64
  "The base library": "The base library",
66
65
  "The core library for Codal-based targets": "The core library for Codal-based targets",
@@ -71,6 +70,7 @@
71
70
  "The programmable LED (WS2812b,APA102) driver.": "The programmable LED (WS2812b,APA102) driver.",
72
71
  "The radio services": "The radio services",
73
72
  "The screen library": "The screen library",
73
+ "Try Now": "Try Now",
74
74
  "Tutorials": "Tutorials",
75
75
  "UART communication": "UART communication",
76
76
  "VM": "VM",