code:
/**
 * Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
 * All rights reserved.
 *
 * For the applicable distribution terms see the license text file included in
 * the distribution.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input.Touch;
using MotoTrialRacer.UI;

namespace MotoTrialRacer
{
    /// <summary>
    /// This class defines the main menu view
    /// Derives from View.
    /// </summary>
    class Menu : View
    {
        private List<Button> buttons = new List<Button>();
        private Button infoButton;
        private const int spacing = 20;

        /// <summary>
        /// Creates a new main menu view
        /// </summary>
        /// <param name="game">The Game instance that will show this view</param>
		public Menu(Game1 game)
			: base(game)
		{
			Vector2 pos = new Vector2(game.getWidth() * 0.88f, 0);
			infoButton = new Button("info", pos, game.Content);
			infoButton.ButtonPressed += (sender => game.ShowInfo());

			if (game.paused && !game.won)
			{
				Button tmp = new Button("resume", pos, game.Content);
				tmp.ButtonPressed += (sender => game.Resume());
				buttons.Add(tmp);
			}

			Button button = new Button("newGame", pos, game.Content);
			button.ButtonPressed += (sender => game.ShowLevelSelector(true));
			buttons.Add(button);

			button = new Button("levelEditor", pos, game.Content);
			button.ButtonPressed += (sender => game.StartLevelEditor());
			buttons.Add(button);

			button = new Button("highScores", pos, game.Content);
			button.ButtonPressed += (sender => game.ShowLevelSelector(false));
			buttons.Add(button);

			button = new Button("exit", pos, game.Content);
			button.ButtonPressed += (sender => game.Exit());
			buttons.Add(button);

			int menuHeight = (buttons.Count - 1) * spacing;
            foreach (Button but in buttons)
            {
			    menuHeight += but.Height;
			}

			pos.Y = game.getHeight() * 0.5f - menuHeight * 0.5f;

			for (int i = 0; i < buttons.Count; i++)
			{
				pos.X = game.getWidth() * 0.5f - buttons[i].Width * 0.5f;
				buttons[i].Position = pos;
				pos.Y += (buttons[i].Height + spacing);
			}
		}

        /// <summary>
        /// Updates all the buttons in this view
        /// </summary>
        public override void Update()
        {
            base.Update();
            infoButton.Update(touchLocation);
            foreach (Button but in buttons)
            {
                but.Update(touchLocation);
            }
        }

        /// <summary>
        /// Draws all the buttons in this view
        /// </summary>
        public override void Draw(SpriteBatch spriteBatch)
        {
			base.Draw(spriteBatch);
			infoButton.Draw(spriteBatch);
            foreach (Button but in buttons)
            {
				but.Draw(spriteBatch);
            }
        }
    }
}


code:
/**
 * Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
 * All rights reserved.
 *
 * For the applicable distribution terms see the license text file included in
 * the distribution.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace MotoTrialRacer
{
    /// <summary>
    /// The class for the splash screen view that is shown when the application is started.
    /// Derives from View.
    /// </summary>
    class SplashScreen : View
    {

        private Texture2D texture;
        private Vector2 pos = Vector2.Zero;
        private int counter = 0;
        private int viewingTime = 120;

        /// <summary>
        /// Creates a new splash screen view
        /// </summary>
        /// <param name="game">The Game instance that will show this view</param>
        public SplashScreen(Game1 game) : base(game)
        {
            texture = game.Content.Load<Texture2D>("Images/splash");
        }

        /// <summary>
        /// Updates the counter of the view.
        /// When the view is shown for two seconds, it's closed.
        /// </summary>
        public override void Update()
        {
            base.Update();
            counter++;
            if (counter == viewingTime)
                game.OpenMenu();
        }

        /// <summary>
        /// Draws the splash screen view
        /// </summary>
		public override void Draw(SpriteBatch spriteBatch)
        {
			base.Draw(spriteBatch);
            spriteBatch.Draw(texture, pos, Color.White);
        }
    }
}

repo_name: snapshot/xnamototrialracer

license: unknown


code:
/**
 * Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
 * All rights reserved.
 *
 * For the applicable distribution terms see the license text file included in
 * the distribution.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input.Touch;
using MotoTrialRacer.UI;

namespace MotoTrialRacer
{
    /// <summary>
    /// The base class for all the views that are shown on top the game world.
    /// Implements the ButtonListener interface
    /// </summary>
    class View : IDrawable
    {
        protected Game1 game;
        protected TouchLocation touchLocation;
        protected bool touchChanged = false;
        private Texture2D background;
        private Rectangle destination;

        /// <summary>
        /// Creates a new view
        /// </summary>
        /// <param name="pGame">The Game instance that will show this view</param>
        public View(Game1 pGame)
        {
            game = pGame;
            destination = new Rectangle(0, 0, pGame.getWidth(), pGame.getHeight() );
            background = new Texture2D(game.GraphicsDevice, 1, 1, false, SurfaceFormat.Color);
            Color[] colors = new Color[background.Width * background.Height];
            for (int i = 0; i < colors.Length; i++)
                colors[i] = new Color(0.0f, 0.0f, 0.0f, 0.4f);
            background.SetData<Color>(colors);
        }

        /// <summary>
        /// Updates the state and location of the touch
        /// </summary>
        public virtual void Update()
        {
            TouchCollection touchCollection = TouchPanel.GetState();

            if (touchCollection.Count() > 0)
            {
                touchLocation = touchCollection[0];
                touchChanged = true;
            }
            else if (touchChanged)
                touchChanged = false;
        }

		public virtual void Draw(SpriteBatch spriteBatch)
		{
			spriteBatch.Draw(background, destination, Color.White);
		}
	}
}


code:
/**
 * Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
 * All rights reserved.
 *
 * For the applicable distribution terms see the license text file included in
 * the distribution.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Graphics;
using MotoTrialRacer.UI;

namespace MotoTrialRacer
{
    /// <summary>
    /// This class defines the view that is shown when the player completes a level.
    /// Derives from View.
    /// </summary>
    class WinView : View
    {
        private Button closeButton;
        private SpriteFont font;
        private TextInput textInput;
        private Vector2 textPos = new Vector2(150, 100);
        private RecordHandler recordHandler;
        private int placement = -1;

        /// <summary>
        /// Creates a new view for telling that the player has completed the level
        /// </summary>
        /// <param name="game">The Game instance that will show this view</param>
        public WinView(Game1 game) : base(game)
        {
            recordHandler = new RecordHandler(game.currentLevelName);
            recordHandler.LoadRecords();
            closeButton = new Button("ok", new Vector2(0, 0), game.Content);
			closeButton.ButtonPressed += new Action<Button>(closeButton_ButtonPressed);

            closeButton.Position = new Vector2(game.getWidth() * 0.5f -
                                                  closeButton.Width * 0.5f,
                                               game.getHeight() * 0.75f);
            textInput = new TextInput("Enter your name here",
                                      new Vector2(game.getWidth() * 0.3f, game.relativeY(200)),
                                      game.Content, (int)(game.getWidth() * 0.4f),
                                      (int)(game.getHeight() * 0.1f));
            font = game.Content.Load<SpriteFont>("SpriteFont2");
            placement = recordHandler.GetPlacement((int)(game.finishTime.TotalMilliseconds));
        }

		void closeButton_ButtonPressed(Button obj)
		{
			game.OpenMenu();
			if (placement != -1 && textInput.Text != textInput.HintText)
			{
				recordHandler.SetRecord(placement, textInput.Text,
										(int)(game.finishTime.TotalMilliseconds));
				recordHandler.SaveRecords();
			}
		}

        /// <summary>
        /// Updates the button and text input UI components
        /// </summary>
        public override void Update()
        {
            base.Update();
            if (touchChanged)
            {
                closeButton.Update(touchLocation);
                textInput.Update(touchLocation);
            }
        }

        /// <summary>
        /// Draws the congratulations text and the time of the level completion.
        /// Also draws the text input for the players name if his/her placement is in the top ten.
        /// </summary>
        public override void Draw(SpriteBatch spriteBatch )
        {
			base.Draw(spriteBatch);
            spriteBatch.DrawString(font, "Your time was " +  String.Format("{0:d2}:{1:d2}:{2:d3}",
                                   game.finishTime.Minutes ,game.finishTime.Seconds,
                                   game.finishTime.Milliseconds), textPos, Color.Yellow);
            if (placement != -1)
            {
				textInput.Draw(spriteBatch);
            }
			closeButton.Draw(spriteBatch);
        }
    }
}


code:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <ProjectGuid>{0515B61A-F0EA-468A-8D35-0DF3A043A158}</ProjectGuid>
    <ProjectTypeGuids>{96E2B04D-8817-42c6-938A-82C39BA4D311};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
    <OutputType>Library</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
    <XnaFrameworkVersion>v4.0</XnaFrameworkVersion>
    <OutputPath>bin\$(Platform)\$(Configuration)</OutputPath>
    <ContentRootDirectory>Content</ContentRootDirectory>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|Windows Phone'">
    <PlatformTarget>x86</PlatformTarget>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|Windows Phone'">
    <PlatformTarget>x86</PlatformTarget>
  </PropertyGroup>
  <PropertyGroup>
    <RootNamespace>MotoTrialRacerContent</RootNamespace>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="Microsoft.Xna.Framework.Content.Pipeline.EffectImporter, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=MSIL">
      <Private>False</Private>
    </Reference>
    <Reference Include="Microsoft.Xna.Framework.Content.Pipeline.FBXImporter, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=MSIL">
      <Private>False</Private>
    </Reference>
    <Reference Include="Microsoft.Xna.Framework.Content.Pipeline.TextureImporter, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=MSIL">
      <Private>False</Private>
    </Reference>
    <Reference Include="Microsoft.Xna.Framework.Content.Pipeline.XImporter, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=MSIL">
      <Private>False</Private>
    </Reference>
    <Reference Include="Microsoft.Xna.Framework.Content.Pipeline.AudioImporters, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=MSIL">
      <Private>False</Private>
    </Reference>
    <Reference Include="Microsoft.Xna.Framework.Content.Pipeline.VideoImporters, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=MSIL">
      <Private>False</Private>
    </Reference>
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Images\arm.png">
      <Name>arm</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\bikeBody.png">
      <Name>bikeBody</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\exit.png">
      <Name>exit</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\exit_select.png">
      <Name>exit_select</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\finish.png">
      <Name>finish</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\grass.png">
      <Name>grass</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\hand.png">
      <Name>hand</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\head.png">
      <Name>head</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\highScores.png">
      <Name>highScores</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\highScores_select.png">
      <Name>highScores_select</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\human.png">
      <Name>human</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\info.png">
      <Name>info</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\info_select.png">
      <Name>info_select</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\jump.png">
      <Name>jump</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\nail.png">
      <Name>nail</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\newGame.png">
      <Name>newGame</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\newGame_select.png">
      <Name>newGame_select</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\ok.png">
      <Name>ok</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\ok_select.png">
      <Name>ok_select</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\options.png">
      <Name>options</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\options_select.png">
      <Name>options_select</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\rearFork.png">
      <Name>rearFork</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\rearWheel.png">
      <Name>rearWheel</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\resume.png">
      <Name>resume</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\resume_select.png">
      <Name>resume_select</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\sky.png">
      <Name>sky</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\splash.png">
      <Name>splash</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\susp_lower.png">
      <Name>susp_lower</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\susp_lower_long.png">
      <Name>susp_lower_long</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\susp_upper.png">
      <Name>susp_upper</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\wheel.png">
      <Name>wheel</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Sounds\motor2.wav">
      <Name>motor2</Name>
      <Importer>WavImporter</Importer>
      <Processor>SoundEffectProcessor</Processor>
    </Compile>
  </ItemGroup>
  <ItemGroup>
    <Compile Include="SpriteFont1.spritefont">
      <Name>SpriteFont1</Name>
      <Importer>FontDescriptionImporter</Importer>
      <Processor>FontDescriptionProcessor</Processor>
      <SubType>Designer</SubType>
    </Compile>
  </ItemGroup>
  <ItemGroup>
    <Compile Include="SpriteFont2.spritefont">
      <Name>SpriteFont2</Name>
      <Importer>FontDescriptionImporter</Importer>
      <Processor>FontDescriptionProcessor</Processor>
      <SubType>Designer</SubType>
    </Compile>
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Sounds\fanfare.wav">
      <Name>fanfare</Name>
      <Importer>WavImporter</Importer>
      <Processor>SoundEffectProcessor</Processor>
    </Compile>
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Sounds\blast.wav">
      <Name>blast</Name>
      <Importer>WavImporter</Importer>
      <Processor>SoundEffectProcessor</Processor>
    </Compile>
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Sounds\ouch.wav">
      <Name>ouch</Name>
      <Importer>WavImporter</Importer>
      <Processor>SoundEffectProcessor</Processor>
    </Compile>
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Sounds\music.wav">
      <Name>music</Name>
      <Importer>WavImporter</Importer>
      <Processor>SoundEffectProcessor</Processor>
    </Compile>
  </ItemGroup>
  <ItemGroup>
    <Compile Include="SpriteFont3.spritefont">
      <Name>SpriteFont3</Name>
      <Importer>FontDescriptionImporter</Importer>
      <Processor>FontDescriptionProcessor</Processor>
    </Compile>
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Images\unZoom.png">
      <Name>unZoom</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\zoom.png">
      <Name>zoom</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Images\save.png">
      <Name>save</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\save_select.png">
      <Name>save_select</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\test.png">
      <Name>test</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\test_select.png">
      <Name>test_select</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Images\bikePos.png">
      <Name>bikePos</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
  </ItemGroup>
  <ItemGroup>
    <None Include="Levels\Level_1.lvl">
      <Name>Level_1</Name>
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
    <None Include="Levels\Level_2.lvl">
      <Name>Level_2</Name>
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
    <None Include="Levels\Level_3.lvl">
      <Name>Level_3</Name>
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Images\back.png">
      <Name>back</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Images\levelEditor.png">
      <Name>levelEditor</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\levelEditor_select.png">
      <Name>levelEditor_select</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Images\level1.png">
      <Name>level1</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\level1_select.png">
      <Name>level1_select</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\level2.png">
      <Name>level2</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\level2_select.png">
      <Name>level2_select</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\level3.png">
      <Name>level3</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\level3_select.png">
      <Name>level3_select</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\myLevels.png">
      <Name>myLevels</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\myLevels_select.png">
      <Name>myLevels_select</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Images\left.png">
      <Name>left</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
    <Compile Include="Images\right.png">
      <Name>right</Name>
      <Importer>TextureImporter</Importer>
      <Processor>TextureProcessor</Processor>
    </Compile>
  </ItemGroup>
  <ItemGroup>
    <Compile Include="infotexts.xml">
      <Name>infotexts</Name>
      <Importer>XmlImporter</Importer>
      <Processor>PassThroughProcessor</Processor>
    </Compile>
  </ItemGroup>
  <ItemGroup />
  <Import Project="$(MSBuildExtensionsPath)\Microsoft\XNA Game Studio\$(XnaFrameworkVersion)\Microsoft.Xna.GameStudio.ContentPipeline.targets" />
  <!--  To modify your build process, add your task inside one of the targets below and uncomment it.
       Other similar extension points exist, see Microsoft.Common.targets.
  <Target Name="BeforeBuild">
  </Target>
  <Target Name="AfterBuild">
  </Target>
  -->
</Project>


code:
<?xml version="1.0" encoding="utf-8"?>
<!--
This file contains an xml description of a font, and will be read by the XNA
Framework Content Pipeline. Follow the comments to customize the appearance
of the font in your game, and to change the characters which are available to draw
with.
-->
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
  <Asset Type="Graphics:FontDescription">

    <!--
    Modify this string to change the font that will be imported.
    -->
    <FontName>Segoe UI Mono</FontName>

    <!--
    Size is a float value, measured in points. Modify this value to change
    the size of the font.
    -->
    <Size>14</Size>

    <!--
    Spacing is a float value, measured in pixels. Modify this value to change
    the amount of spacing in between characters.
    -->
    <Spacing>0</Spacing>

    <!--
    UseKerning controls the layout of the font. If this value is true, kerning information
    will be used when placing characters.
    -->
    <UseKerning>true</UseKerning>

    <!--
    Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
    and "Bold, Italic", and are case sensitive.
    -->
    <Style>Bold</Style>

    <!--
    If you uncomment this line, the default character will be substituted if you draw
    or measure text that contains characters which were not included in the font.
    -->
    <!-- <DefaultCharacter>*</DefaultCharacter> -->

    <!--
    CharacterRegions control what letters are available in the font. Every
    character from Start to End will be built and made available for drawing. The
    default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
    character set. The characters are ordered according to the Unicode standard.
    See the documentation for more information.
    -->
    <CharacterRegions>
      <CharacterRegion>
        <Start> </Start>
        <End>~</End>
      </CharacterRegion>
    </CharacterRegions>
  </Asset>
</XnaContent>


code:
<?xml version="1.0" encoding="utf-8"?>
<!--
This file contains an xml description of a font, and will be read by the XNA
Framework Content Pipeline. Follow the comments to customize the appearance
of the font in your game, and to change the characters which are available to draw
with.
-->
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
  <Asset Type="Graphics:FontDescription">

    <!--
    Modify this string to change the font that will be imported.
    -->
    <FontName>Segoe UI Mono</FontName>

    <!--
    Size is a float value, measured in points. Modify this value to change
    the size of the font.
    -->
    <Size>26</Size>

    <!--
    Spacing is a float value, measured in pixels. Modify this value to change
    the amount of spacing in between characters.
    -->
    <Spacing>0</Spacing>

    <!--
    UseKerning controls the layout of the font. If this value is true, kerning information
    will be used when placing characters.
    -->
    <UseKerning>true</UseKerning>

    <!--
    Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
    and "Bold, Italic", and are case sensitive.
    -->
    <Style>Regular</Style>

    <!--
    If you uncomment this line, the default character will be substituted if you draw
    or measure text that contains characters which were not included in the font.
    -->
    <!-- <DefaultCharacter>*</DefaultCharacter> -->

    <!--
    CharacterRegions control what letters are available in the font. Every
    character from Start to End will be built and made available for drawing. The
    default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
    character set. The characters are ordered according to the Unicode standard.
    See the documentation for more information.
    -->
    <CharacterRegions>
      <CharacterRegion>
        <Start> </Start>
        <End>~</End>
      </CharacterRegion>
    </CharacterRegions>
  </Asset>
</XnaContent>


code:
<?xml version="1.0" encoding="utf-8"?>
<!--
This file contains an xml description of a font, and will be read by the XNA
Framework Content Pipeline. Follow the comments to customize the appearance
of the font in your game, and to change the characters which are available to draw
with.
-->
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
  <Asset Type="Graphics:FontDescription">

    <!--
    Modify this string to change the font that will be imported.
    -->
    <FontName>QUARTZ MS</FontName>

    <!--
    Size is a float value, measured in points. Modify this value to change
    the size of the font.
    -->
    <Size>26</Size>

    <!--
    Spacing is a float value, measured in pixels. Modify this value to change
    the amount of spacing in between characters.
    -->
    <Spacing>0</Spacing>

    <!--
    UseKerning controls the layout of the font. If this value is true, kerning information
    will be used when placing characters.
    -->
    <UseKerning>true</UseKerning>

    <!--
    Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
    and "Bold, Italic", and are case sensitive.
    -->
    <Style>Regular</Style>

    <!--
    If you uncomment this line, the default character will be substituted if you draw
    or measure text that contains characters which were not included in the font.
    -->
    <!-- <DefaultCharacter>*</DefaultCharacter> -->

    <!--
    CharacterRegions control what letters are available in the font. Every
    character from Start to End will be built and made available for drawing. The
    default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
    character set. The characters are ordered according to the Unicode standard.
    See the documentation for more information.
    -->
    <CharacterRegions>
      <CharacterRegion>
        <Start> </Start>
        <End>~</End>
      </CharacterRegion>
    </CharacterRegions>
  </Asset>
</XnaContent>


code:
<?xml version="1.0" encoding="utf-8" ?>
<XnaContent>
  <Asset Type="System.String" Name="infoString">Moto Trial Racer XNA

Moto Trial Racer XNA is a motorcycle racing
game which uses Box2D.XNA physics engine.
See more information about the project at
https://projects.developer.nokia.com/xnamototrialracer.

Playing Moto Trial Racer

The Goal is to get the motorcycle and the
driver to the chequered flag as fast as
possible. The game ends if any part of
the motorcycle or player touches the
spikes or the player's head touches any
other object. When the player gets to
the chequered flag fast enough, he/she
gets his/her name and time to the high
scores list. The game can be paused,
restarted and exited at any time via the
options menu.

Controls

The motorcycle is accelerated by leaning
the device towards the player and
braked by leaning the device away from
the player. The center of mass can be
moved backwards/forwards by pressing the
arrow buttons in top of the screen.

Level Editor

New objects can be added by pressing the
object buttons in top of the screen. After
a new object is added, it can be dragged
to any position. An active object can be
rotated by using two fingers. When the
level is completed, it can be named and saved.
The custom levels can be deleted by pressing
and holding a level button down for two seconds.
</Asset>
</XnaContent>


code:
Moto Trial Racer XNA
====================

Moto Trial Racer XNA is a motorcycle racing game on Windows Phone 7 & XNA Game
Studio 4.0, demonstrating especially the use of Box2D.XNA, an XNA binding for
the Box2D physics engine. This application has been ported from a
corresponding Qt/QML example, and thereby also demonstrates and provides
guidance on the porting and co-development between Qt and Windows Phone. The
application's graphics are reused from the QML version.

The game has three predefined levels and a level editor with which the user
can create as many new levels as he/she likes.

The example has been developed with Microsoft Visual Studio 2010 Express for
Windows Phone and tested to work on Windows Phone 7.

This project is hosted in a Nokia Developer Project at
http://projects.developer.nokia.com/xnamototrialracer

For more information about the implementation see the project wiki page:
- http://projects.developer.nokia.com/xnamototrialracer/wiki

PLAYING MOTO TRIAL RACER
-------------------------------------------------------------------------------

The goal is to get the motorcycle and the driver to the chequered flag as fast
as possible. The game ends if any part of the motorcycle or player touches the
spikes, or if the player's head touches any other object. When the player gets
to the chequered flag fast enough, he/she gets his/her name and time on the
high scores list. The game can be paused, restarted, and exited at any time
via the options menu.

The motorcycle is accelerated by tilting the device towards the player and
braked by tilting the device away from the player. The center of mass can be
moved backwards/forwards by pressing the arrow buttons in the top corners of
the game screen.

Level Editor:
	New objects can be added by pressing the object buttons in the top of
	the screen. After a new object is added, it can be dragged to any
	position. An active object can be rotated by using two fingers. When
	the level is completed, it can be named and saved. The custom levels
	can be deleted by pressing and holding down a level button in the
	level selecting view for two seconds.

PREREQUISITES
-------------------------------------------------------------------------------

- C# basics
- Development environment 'Microsoft Visual Studio 2010 Express for Windows
  Phone'

LINKS
-------------------------------------------------------------------------------

Getting Started Guide:
http://create.msdn.com/en-us/home/getting_started

Learn About Windows Phone 7 Development:
http://msdn.microsoft.com/fi-fi/ff380145

App Hub, develop for Windows Phone:
http://create.msdn.com

Game Development:
http://create.msdn.com/en-us/education/gamedevelopment

IMPORTANT FILES/CLASSES
-------------------------------------------------------------------------------

Game1.cs:		The main game class derived from Microsoft.Xna.Framework.Game.
			In this class the game content is loaded, game update requests
			are received, the drawing is handled, the game mechanics like
			timing, winning, and failing are implemented, and all the
			views are handled.

Level.cs:		All handling of the game world and physics is done in this
			class.

Bike.cs:		This class defines all the parts of the motorcycle and the
			driver, all the joints between the parts, and all behaviour of
			the parts and joints.

LevelEditor.cs:		The class that defines the level editor allowing to create
			own custom levels.

RotationData.cs:	This class handles the acceleration sensor data of the device

World.cs:		The world class manages all physics entities, dynamic simulation,
    			and asynchronous queries. The world also contains efficient
			memory management facilities.

KNOWN ISSUES
-------------------------------------------------------------------------------

None.

BUILD & INSTALLATION INSTRUCTIONS
-------------------------------------------------------------------------------

Preparations
~~~~~~~~~~~~

Make sure you have the following installed:
 * Windows 7, may also work on Windows XP
 * Microsoft Visual Studio 2010 Express for Windows Phone
 * The Windows Phone Software Development Kit (SDK) 7.1
   http://go.microsoft.com/?linkid=9772716

Build on Microsoft Visual Studio
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Please refer to:
http://msdn.microsoft.com/en-us/library/ff928362.aspx

Deploy to Windows Phone 7
~~~~~~~~~~~~~~~~~~~~~~~~~
Please refer to:
http://msdn.microsoft.com/en-us/library/gg588378.aspx

ACCELEROMETER
-------------------------------------------------------------------------------
The application heavily bases on accelerometer sensor. Please follow the link
below for instruction about using accelerometer in applcations. Accelerometer
can be also tested now on the Windows Phone Emulator.

http://msdn.microsoft.com/en-us/library/ff431810.aspx

COMPATIBILITY
-------------------------------------------------------------------------------

- Windows Phone 7
- XNA Game Studio 4.0

Tested on:
- HTC 7 Mozart
- LG Optimus 7
- Samsung Omnia 7

Developed with:
- Microsoft Visual Studio 2010 Express for Windows Phone

LICENCE
-------------------------------------------------------------------------------
You can find license details in Licence.txt file provided with this project
or online at
http://projects.developer.nokia.com/xnamototrialracer/browser/Licence.txt

CHANGE HISTORY
-------------------------------------------------------------------------------

1.2 Code level improvements
1.1 General improvements on code level
1.0 The first non-beta version
0.4 Some bugs related to the level editor are fixed
0.3 The levels and the corresponding high scores can be saved and loaded
0.2 The first beta version of the level editor is added
0.1 The initial version


code:
# *TurboSnap!*

*TurboSnap! Makes your projects go to warp 9!*

A project to compile [*Snap!*](https://snap.berkeley.edu/) projects to JavaScript.

### Contributing
Read [contributing.md](https://notabug.org/madpickle/TurboSnap/src/master/contributing.md) if you want to contribute.

repo_name: pkhead/TurboSnap

license: wtfpl


code:
## Contributing to *TurboSnap!*
If you want to contribute to *TurboSnap!*, Ask sir_kitten2 on the [Official Forum Topic](https://forum.snap.berkeley.edu/t/turbosnap/9002).

### Contributing Guidelines
* If it's anything other than a bugfix, please make a pull request before commiting.
* If there's an issue you can't solve, submit an issue.
* Please respect everyone else at all times.


code:
<!DOCTYPE html>

    <title>TurboSnap!</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <link href="style.css" rel="stylesheet">

            Home

            Run

           Contribute

TurboSnap!

TurboSnap! is an online tool for compiling Snap! projects to JavaScript.

            <button onclick="loadProject();" type="button" class="btn btn-primary">Load</button>
            <button onclick="runProject();" type="button" class="btn btn-success">Run</button>
            <button onclick="stopProject();" type="button" class="btn btn-danger">Stop</button>

        <canvas id="canvas" width="480" height="360"></canvas>


code:
// TODO What is this context id stuff in globals xml
// What it saves the block context for custom blocks in the xml

function parseXml(xml) {
    var domParser = new DOMParser();
    return domParser.parseFromString(xml, "text/xml");
}

var GeneratorFunction = Object.getPrototypeOf(function*(){}).constructor;

/*
import("/turbosnap/script-compiler.js")
.then((module) => {
    var xml = parseXml(TEST);
    var defXml = parseXml(DEF_TEST);

    var globalScope = new module.Scope();
    globalScope.prefix = "env.globals.";
    globalScope.addVariable("a");

    var defSrc = module.compileDefinition(defXml.firstChild, globalScope);
    console.log(defSrc);

    var src = module.compileScript(xml.firstChild, globalScope);
    console.log(src);

    //var genFunc = new GeneratorFunction("env", src);
    //var task = genFunc(script_env);

    //runTask(task);
});
*/

import("/turbosnap/project.js").then((module) => {
    fetch("examples/sierpinski.xml").then(res => res.text())
        .then(data => {
            var canvas = document.getElementById("canvas");

            var xml = parseXml(data).firstChild;
            var project = new module.Project(canvas);
            project.loadXml(xml);
            console.log(project);

            window.addEventListener("keydown", (ev) => project.keyDown(ev));
            window.addEventListener("keyup", (ev) => project.keyUp(ev));
            canvas.addEventListener("mousedown", (ev) => project.mouseDown(ev));
            canvas.addEventListener("mouseup", (ev) => project.mouseUp(ev));
            window.addEventListener("mousemove", (ev) => project.mouseMove(ev));

            window.runProject = function() {
                project.go();
            };

            window.stopProject = function() {
                project.stop();
            };

            window.loadProject = function() {
                var input = prompt("enter [username]/[project name]");

                var [username, projectName] = input.split("/");

                if (projectName) {
                    fetch(`https://snap.berkeley.edu/api/v1/projects/${username}/${projectName}`)
                        .then(res => res.text())
                        .then(data => {
                            var xml = parseXml(data).firstChild.firstChild;
                            project.reset();
                            project.loadXml(xml);
                        });
                } else {
                    fetch(`examples/${username}.xml`)
                        .then(res => res.text())
                        .then(data => {
                            var xml = parseXml(data).firstChild;
                            project.reset();
                            project.loadXml(xml);
                        })
                }
            }

            var last = performance.now();

            // TODO: opengl drawing
            (function update(now) {
                requestAnimationFrame(update);
                var dt = now - last;
                last = now;
                project.tick(dt);
                project.render(canvas);
            })(last);
        })
});


code:
.heading {
    text-align: center;
}

 .img-align {
  display: block;
  margin-left: auto;
  margin-right: auto;
  width: 30%;
}

#logo-img {
    margin-top: 55px;
    margin-bottom: 55px;
}

#canvas {
    padding-left: 0;
    padding-right: 0;
    margin-left: auto;
    margin-right: auto;
    display: block;
    width: 480px;
    border-style: solid;
    border-color: #222222;
}

#canvas-buttons {
    margin: 0 auto;
    margin-bottom: 15px;
    width: 220px;
}


code:
class Color {
    constructor(r, g, b, a = 1) {
        this.r = r;
        this.g = g;
        this.b = b;
        this.a = a;
    }

    toRGBString() {
        return `rgb(${this.r}, ${this.g}, ${this.b})`;
    }

    toRGBAString() {
        return `rgba(${this.r}, ${this.g}, ${this.b}, ${this.a})`;
    }
}

export { Color }


code:
class Costume {
    constructor(name = "Costume") {
        this.name = name;
        this.canvas = null;
    }

    get width() {
        return this.canvas.width;
    }

    get height() {
        return this.canvas.height;
    }

    load(src) {
        return new Promise((resolve, reject) => {
            var image = new Image();
            var self = this;

            image.onload = function() {
                self.canvas = document.createElement("canvas");
                self.canvas.width = image.width;
                self.canvas.height = image.height;
                self.canvas.getContext("2d").drawImage(image, 0, 0);
                resolve(self);
            }

            image.src = src;
        });
    }
}

export { Costume }


code:
import { compileScript, getScriptEvent, Scope } from "./script-compiler.js";
import { Costume } from "./costume.js";

function _scriptRandom(min, max) {
    return Math.floor(Math.random() * (max - min)) + min;
}

function _scriptSum(...args) {
    var res = 0;
    var isArr = false;
    var arr0, arr1;

    for (let arg of args) {
        if (isArr) {
            if (Array.isArray(arg)) {
                // target array is array with least items
                if (arg.length > res.length) {
                    arr0 = res;
                    arr1 = arg;
                } else {
                    arr0 = arg;
                    arr1 = res;
                }

                res = arr0.map((v, i) => v + arr1[i]);
            } else {
                res = res.map(v => v + arg);
            }
        } else {
            if (Array.isArray(arg)) {
                isArr = true;

                res = arg.map(v => v + res);
            } else {
                res += arg;
            }
        }
    }

    return res;
}

function _scriptProduct(...args) {
    var res = 1;
    var isArr = false;
    var arr0, arr1;

    for (let arg of args) {
        if (isArr) {
            if (Array.isArray(arg)) {
                // target array is array with least items
                if (arg.length > res.length) {
                    arr0 = res;
                    arr1 = arg;
                } else {
                    arr0 = arg;
                    arr1 = res;
                }

                res = arr0.map((v, i) => v * arr1[i]);
            } else {
                res = res.map(v => v * arg);
            }
        } else {
            if (Array.isArray(arg)) {
                isArr = true;

                res = arg.map(v => v * res);
            } else {
                res *= arg;
            }
        }
    }

    return res;
}

function _scriptSubtract(a, b) {
    var isArr_a = Array.isArray(a);
    var isArr_b = Array.isArray(b);

    if (isArr_a && isArr_b) {
        let arr0, arr1;

        // target array is array with least items
        if (arg.length > res.length) {
            arr0 = res;
            arr1 = arg;
        } else {
            arr0 = arg;
            arr1 = res;
        }

        return arr0.map((v, i) => v - arr1[i]);
    } else if (isArr_a) {
        return a.map(v => v - b);
    } else if (isArr_b) {
        return b.map(v => a - v);
    } else {
        return a - b;
    }
}

function _scriptDivide(a, b) {
    var isArr_a = Array.isArray(a);
    var isArr_b = Array.isArray(b);

    if (isArr_a && isArr_b) {
        let arr0, arr1;

        // target array is array with least items
        if (arg.length > res.length) {
            arr0 = res;
            arr1 = arg;
        } else {
            arr0 = arg;
            arr1 = res;
        }

        return arr0.map((v, i) => v / arr1[i]);
    } else if (isArr_a) {
        return a.map(v => v / b);
    } else if (isArr_b) {
        return b.map(v => a / v);
    } else {
        return a / b;
    }
}

function _scriptListDelete(arr, index) {
    if (index === "last") {
        arr.pop();
    } else if (index === "all") {
        arr.splice(0, arr.length);
    } else {
        arr.splice(+index-1, 1);
    }
}

function _scriptListGet(arr, index) {
    if (index === "last") {
        return arr[arr.length - 1];
    }

    if (index === "random") {
        return arr[Math.floor(Math.random() * arr.length)];
    }

    return arr[+index-1];
}

const SCRIPT_OP_MAPPINGS = {
    abs: Math.abs,
    neg: v => -v,
    sign: Math.sign,
    ceiling: Math.ceil,
    floor: Math.floor,
    sqrt: Math.sqrt,
    sin: v => Math.sin(+v / 180 * Math.PI),
    cos: v => Math.cos(+v / 180 * Math.PI),
    tan: v => Math.tan(+v / 180 * Math.PI),
    asin: v => Math.asin(v) / Math.PI * 180,
    acos: v => Math.acos(v) / Math.PI * 180,
    atan: v => Math.atan(v) / Math.PI * 180,
    ln: Math.log,
    log: Math.log10,
    lg: Math.log2,
    ["e^"]: Math.exp,
    ["10^"]: v => 10^(+v),
    ["2^"]: v => 2^(+v),
    id: (item) => {
        if (Array.isArray(item)) {
            return [...item];
        }

        return item;
    },
}

var TaskSpawner = Object.getPrototypeOf(function*(){}).constructor;

class SnapObject {
    constructor(parent) {
        this.name = "Object";
        this.varScope = new Scope(parent.varScope);

        this.parent = parent;
        this.costumes = [];
        this.sounds = [];
        this.functions = new Map();
        this.listeners = {};

        this.curCostume = null;
        this.shown = true;
        this.effects = {
            color: 0,
            saturation: 0,
            brightness: 0,
            fisheye: 0,
            whirl: 0,
            pixelate: 0,
            mosaic: 0,
            ghost: 0,
            negative: 0
        };

        var self = this;

        this.scriptEnv = {
            ops: SCRIPT_OP_MAPPINGS,

            *wait(s) {
                if (s === undefined) {
                    s = 0;
                } else {
                    s = +s;
                    if (Number.isNaN(s))
                        throw new TypeError("Not a number");
                }

                if (self.getProject().warped) return;

                yield 1000*s;
            },

            sum: _scriptSum,
            product: _scriptProduct,
            subtract: _scriptSubtract,
            divide: _scriptDivide,
            random:  _scriptRandom,

            // listInsert
            // listReplace
            listDelete: _scriptListDelete,
            listGet: _scriptListGet,

            getFunc(opcode) {
                return self.getFunction(opcode).func;
            },

            pushWarp() {
                self.getProject().pushWarp();
            },

            popWarp() {
                self.getProject().popWarp();
            },

            mouseX() {
                return self.getProject().mouseX;
            },

            mouseY() {
                return self.getProject().mouseY;
            },

            mouseDown() {
                return self.getProject().mouseDown;
            },

            keyPressed(key) {
                return self.getProject().isKeyDown(key);
            },

            resetTimer() {
                self.getProject().timer = 0;
            },

            timer() {
                return self.getProject().timer / 1000;
            },

            setCostume(name) {
                console.log(self.costumes);
                if (name === "Turtle") {
                    self.curCostume = null;
                } else {
                    self.curCostume = self.getCostume(name);
                }
            },

            nextCostume() {
                var idx = self.getCostumeIndex();
                if (idx >= 0) {
                    self.curCostume = self.costumes[(idx + 1) % self.costumes.length];
                }
            },

            show() {
                self.shown = true;
            },

            hide() {
                self.shown = false;
            },

            changeEffect(effect, val) {
                self.effects[effect] += val / 100;
            },

            setEffect(effect, val) {
                self.effects[effect] = val / 100;
            },

            getEffect(effect) {
                return self.effects[effect] * 100;
            },

            clearEffects() {
                self.effects.color = 0;
                self.effects.saturation = 0;
                self.effects.brightness = 0;
                self.effects.ghost = 0;
                self.effects.fisheye = 0;
                self.effects.whirl = 0;
                self.effects.pixelate = 0;
                self.effects.mosaic = 0;
                self.effects.negative = 0;
            },
        }
    }

    async loadXml(xml) {
        this.name = xml.attributes.name.nodeValue;

        for (let child of xml.children) {
            switch (child.nodeName) {
                case "variables": {
                    // TODO
                    break;
                }

                case "sounds": {
                    // TODO
                    break;
                }

                case "costumes": {
                    let listNode = child.firstElementChild;

                    for (let itemNode of listNode.children) {
                        let costumeNode = itemNode.firstElementChild;
                        let costume = new Costume(costumeNode.attributes.name.nodeValue);
                        await costume.load(costumeNode.attributes.image.nodeValue);
                        this.costumes.push(costume);
                    }
                    break;
                }

                case "scripts": {
                    for (let scriptNode of child.children) {
                        // TODO
                        let evData = getScriptEvent(scriptNode);
                        if (evData) {
                            console.group("script compilation");

                            try {
                                let scope = new Scope(this.varScope);

                                // add event parameters into scope
                                let safeParamNames = [];

                                for (let paramName of evData.params) {
                                    safeParamNames.push(scope.addVariable(paramName));
                                }

                                let compiled = compileScript(scriptNode, scope);
                                console.log(compiled);

                                let func = new TaskSpawner("env", ...safeParamNames, compiled);

                                /*this.onEvent(evData.name, (val) => {
                                    if (val === evData.value) {
                                        console.log("Run", func);
                                        this.getProject().runTask(func(this.scriptEnv));
                                    }
                                });*/
                                console.log(evData);
                                this.bindEvent(evData.name, evData.value, func, this.scriptEnv);
                            } catch(err) {
                                console.error(err);
                            }

                            console.groupEnd("script compilation");
                        }
                    }

                    break;
                }
            }
        }

        // set current costume
        var costumeNum = +xml.attributes.costume.nodeValue;
        this.curCostume = costumeNum > 0 ? this.costumes[costumeNum-1] : null;
    }

    getProject() {
        throw new Error("getProject() not implemented");
    }

    getFunction(fname) {
        var res = this.functions.get(fname);
        if (res) return res.func;

        return this.parent.getFunction(fname);
    }

    getCostumeIndex() {
        if (!this.curCostume) return -1;
        return this.costumes.indexOf(this.curCostume);
    }

    getCostume(name) {
        return this.costumes.find(v => v.name == name);
    }

    /*
    onEvent(name, callback) {
        var arr = this.listeners[name];

        if (!arr) {
            arr = [];
            this.listeners[name] = arr;
        }

        arr.push(callback);
    }
    */

    applyEffects(ctx) {
        ctx.globalAlpha = 1 - this.effects.ghost;
    }

    bindEvent(name, value, func, ...args) {
        var arr = this.listeners[name];

        if (!arr) {
            arr = [];
            this.listeners[name] = arr;
        }

        arr.push({val: value, func: func, args: [...args]});
    }

    fireEvent(name, value, ...args) {
        var callbacks = this.listeners[name];

        this.scriptEnv.globals = this.scene.variables;

        if (callbacks) {
            for (let callback of callbacks) {
                if (value === callback.val) {
                    console.log(...callback.args, ...args);
                    this.getProject().runTask(callback.func(...callback.args, ...args));
                }
            }
        }
    }

    *fireEventSync(name, value, ...args) {
        var callbacks = this.listeners[name];

        if (callbacks) {
            for (let callback of callbacks) {
                if (value === callback.val) {
                    yield* callback.func(...callback.args);
                }
            }
        }
    }
}

export { SnapObject }


code:
import { Scene } from "./scene.js"

const KEY_MAPS = {
    Space: "space",
    ArrowRight: "right arrow",
    ArrowLeft: "left arrow",
    ArrowUp: "up arrow",
    ArrowDown: "down arrow",
    Enter: "enter",
    Plus: "+",
    Minus: "-",
};

var char = str => str.charCodeAt(0);

// generate character keys
for (let n = char("a"); n < char("z"); n++) {
    let c = String.fromCharCode(n);
    KEY_MAPS["Key" + c.toUpperCase()] = c;
}

// generate number keys
for (let i = 0; i < 9; i++) {
    KEY_MAPS["Key" + i] = i.toString();
}

console.log(KEY_MAPS);

class Project {
    constructor(canvas) {
        this.mouseX = 0;
        this.mouseY = 0;
        this._mouseDown = false;
        this.keys = new Set();

        this.canvas = canvas;

        this.reset();
    }

    async loadXml(xml) {
        if (xml.nodeName !== "project") throw new Error("Expected <project> tag");

        for (let node of xml.children) {
            if (node.nodeName === "scenes") {
               // create scenes
               for (let sceneNode of node.children) {
                   var scene = new Scene(this);
                   scene.loadXml(sceneNode);
                   this.scenes.push(scene);
               }
            }
        }

        this.updateSize();
    }

    reset() {
        this.scenes = [];
        this.sceneNum = 0;
        this.scheduledTasks = [];
        this.warpLevel = 0;
        this.timer = 0;
    }

    tick(dt) {
        this.timer += dt;

        for (let i = this.scheduledTasks.length - 1; i >= 0; i--) {
            let v = this.scheduledTasks[i];
            v[1] -= dt;

            if (v[1] <= 0) {
                this.scheduledTasks.splice(i, 1);
                this.runTask(v[0], dt);
            }
        }
    }

    runTask(task, arg) {
        var res = task.next(arg);
        if (res.done) return;

        var waitTime = res.value || 0;
        this.scheduledTasks.push([task, waitTime]);
    }

    get scene() {
        return this.scenes[this.sceneNum];
    }

    get stage() {
        return this.scene.stage;
    }

    go() {
        this.stop();
        this.stage.broadcast("message", "__shout__go__");
    }

    stop() {
        this.scheduledTasks = [];
    }

    pushWarp() {
        this.warpLevel++;
    }

    popWarp() {
        this.warpLevel--;
        if (this.warpLevel < 0) this.warpLevel = 0;
    }

    get warped() {
        return this.warpLevel > 0;
    }

    updateSize() {
        var width = this.stage.width;
        var height = this.stage.height;

        // update canvas
        this.canvas.width = width * window.devicePixelRatio;
        this.canvas.height = height * window.devicePixelRatio;
        this.canvas.style.width = `${width}px`;
        this.canvas.style.height = `${height}px`;
    }

    render() {
        var canvas = this.canvas;
        var ctx = canvas.getContext("2d");
        ctx.resetTransform();
        ctx.scale(window.devicePixelRatio, window.devicePixelRatio);

        // TODO make this an option
        ctx.imageSmoothingEnabled = true;

        ctx.fillStyle = "black";
        ctx.fillRect(0, 0, canvas.width, canvas.height);

        var scene = this.scene;
        var stage = scene.stage
        stage.render(canvas, ctx);
    }

    isKeyDown(k) {
        return this.keys.has(k);
    }

    keyDown(ev) {
        var map = KEY_MAPS[ev.code];

        if (map) {
            this.keys.add(map);
            this.stage.broadcast("keydown", "any key", map);
            this.stage.broadcast("keydown", map);
        }
    }

    keyUp(ev) {
        var map = KEY_MAPS[ev.code];

        if (map) {
            this.keys.delete(map);
        }
    }

    mouseMove(ev) {
        var mouseX = ev.pageX - this.canvas.offsetLeft;
        var mouseY = ev.pageY - this.canvas.offsetTop;

        this.mouseX = mouseX - this.canvas.width / 2;
        this.mouseY = -(mouseY - this.canvas.height / 2);
    }

    mouseDown(ev) {
        this._mouseDown = true;
    }

    mouseUp(ev) {
        this._mouseDown = false;
    }
}

export { Project };


code:
import { compileDefinition, compileScript, Scope } from "./script-compiler.js";
import { Stage } from "./stage.js";

class Scene {
    constructor(project) {
        this.project = project;
        this.stage = null;
        this.functions = new Map();

        this.variables = {};

        this.varScope = new Scope();
        this.varScope.prefix = "env.globals.";
    }

    async loadXml(xml) {
        if (xml.nodeName !== "scene") throw new Error("Expected <scene> tag");

        var blocksNode, stageNode;

        for (let child of xml.children) {
            switch (child.nodeName) {
                case "stage": {
                    stageNode = child;
                    break;
                }

                case "blocks": {
                    blocksNode = child;
                    break;
                }

                case "variables": {
                    for (let varNode of child.children) {
                        let varName = varNode.attributes.name.nodeValue;
                        let safeVarName = this.varScope.addVariable(varName);

                        // remove prefix
                        safeVarName = safeVarName.slice(this.varScope.prefix.length);

                        let val = varNode.firstElementChild;
                        if (val) {
                            console.log(varNode);
                            let compiled = compileScript(varNode.firstElementChild);

                            console.log(`set ${safeVarName} to ${compiled}`);
                            this.variables[safeVarName] = eval(compiled);
                        } else {
                            this.variables[safeVarName] = 0;
                        }
                    }

                    break;
                }
            }
        }

        this.stage = new Stage(this);
        this.stage.loadXml(stageNode);

        // compile blocks after initializing stage
        // that is because global variables are defined in the stage
        for (let blockNode of blocksNode.children) {
            console.group("block compilation");

            try {
                var def = compileDefinition(blockNode, this.stage.varScope);

                this.functions.set(def.opcode, {
                    paramTypes: def.paramTypes,
                    func: def.func
                });
            } catch(err) {
                console.error(err);
            }

            console.groupEnd();
        }
    }

    getFunction(fname) {
        return this.functions.get(fname);
    }
}

export { Scene }


code:
const OPCODE_MAPPINGS = {
    forward: "env.sprite.forward",
    turn: "env.sprite.turn",
    turnLeft: "env.sprite.turnLeft",
    setHeading: "env.sprite.setHeading",
    doFaceTowards: "env.sprite.faceTowards",
    gotoXY: "env.sprite.gotoXY",
    doGotoObject: "env.sprite.goto",
    doGlide: "yield* env.sprite.glide",
    changeXPosition: "env.sprite.changeX",
    setXPosition: "env.sprite.setX",
    changeYPosition: "env.sprite.changeY",
    setYPosition: "env.sprite.setY",
    bounceOffEdge: "env.sprite.bounceOffEdge",

    doSwitchToCostume: "env.setCostume",
    doWearNextCostume: "env.nextCostume",
    doSayFor: "yield* env.sprite.sayFor",
    bubble: "env.sprite.bubble",
    doThinkFor: "yield* env.sprite.thinkFor",
    doThink: "env.sprite.think",
    changeEffect: "env.changeEffect",
    setEffect: "env.setEffect",
    clearEffects: "env.clearEffects",
    getEffect: "env.getEffect",
    changeScale: "env.sprite.changeScale",
    setScale: "env.sprite.setScale",
    getScale: "env.sprite.getScale",
    show: "env.show",
    hide: "env.hide",
    reportShown: "env.isShown",
    goToLayer: "env.sprite.setLayer",
    goBack: "env.sprite.goBack",

    playSound: "env.sprite.playSound",
    doPlaySoundUntilDone: "yield* env.sprite.playSoundAndWait",
    doStopAllSounds: "env.sprite.stopAllSounds",

    clear: "env.penClear",
    down: "env.sprite.penDown",
    up: "env.sprite.penUp",
    getPenDown: "env.sprite.isPenDown",
    setColor: "env.sprite.setPenColor",
    changeSize: "env.sprite.changePenSize",
    setSize: "env.sprite.setPenSize",
    doStamp: "env.sprite.stamp",
    floodFill: "env.sprite.floodFill",
    write: "env.sprite.write",

    doAsk: "env.ask",
    getLastAnswer: "env.lastAnswer",
    reportMouseX: "env.mouseX",
    reportMouseY: "env.mouseY",
    reportMouseDown: "env.mouseDown",
    reportKeyPressed: "env.keyPressed",
    doResetTimer: "env.resetTimer",
    getTimer: "env.timer",

    doBroadcast: "env.broadcast",
    doBroadcastAndWait: "yield* env.broadcastWait",
    doWait: "yield* env.wait",

    reportRandom: "env.random",
};

const YIELD_CODE = "yield* env.wait();";

const EVENT_OPCODES = [
    "receiveGo", "receiveKey", "receiveInteraction", "receiveMessage"
];

var shared;

function compileParam(scope, node, i) {
    return compileItem(scope, node.children[i]);
}

function concatList(scope, listNode, separator, f = compileItem) {
    var res = "";
    var items = listNode.children;

    for (let i = 0; i < items.length; i++) {
        let v = items[i];

        res += f(scope, v);
        if (i < items.length - 1) res += separator;
    }

    return res;
}

class Scope {
    constructor(parent) {
        this.parent = parent;
        this.usedNames = new Set();
        this.vars = new Map();

        this.prefix = "_";

        // for implicit arguments
        this.params = [];
        this.paramIndex = 0;
    }

    addVariable(varName) {
        let safeBase = this.prefix + varName.replaceAll(/[^A-Za-z0-9_]/ig, "_");

        let num = 0;
        let safe = safeBase;

        while (this.hasSafeName(safe)) {
            safe = safeBase + `$${num}`;
            num++;
        }

        this.usedNames.add(safe);
        this.vars.set(varName, safe);

        return safe;
    }

    addParam(varName) {
        var res = this.addVariable(varName)
        this.params.push(res);
        return res;
    }

    getImplictArgument() {
        if (this.paramIndex >= this.params.length) return "";
        return this.params[this.paramIndex++];
    }

    hasSafeName(safeName) {
        if (this.usedNames.has(safeName)) {
            return true;
        } else {
            return this.parent ? this.parent.hasSafeName(safeName) : false;
        }
    }

    get(varName, recursive = true) {
        var res = this.vars.get(varName);

        if (!res && this.parent && recursive) {
            return this.parent.get(varName, recursive);
        }

        return res;
    }
}

function compileUpvar(scope, itemNode) {
    return scope.addVariable(itemNode.textContent);
}

function compileInputName(scope, itemNode) {
    return scope.addParam(itemNode.textContent);
}

function compileItem(scope, itemNode) {
    switch (itemNode.nodeName) {
        // text/number
        case "l": {
            // if child is an option node, return value of option node
            var optionNode = itemNode.children[0];
            if (optionNode && optionNode.nodeName === "option") {
                return `"${optionNode.textContent}"`;
            }

            // TODO string escape characters
            let res = itemNode.textContent;

            if (res === "") {
                return scope.getImplictArgument();
            } else {
                return Number.isNaN(+res) ? `"${res}"` : `${res}`;
            }
        }

        case "script": {
            var out = "";

            for (let node of itemNode.children) {
                out += compileItem(scope, node) + ";\n";
            }

            return out;
        }

        case "autolambda": {
            return compileItem(scope, itemNode.firstElementChild);
        }

        case "block": {
            // if this is a variable get block
            if (itemNode.attributes.var) {
                let varName = itemNode.attributes.var.nodeValue;
                let safeName = scope.get(varName);

                if (!safeName) {
                    throw new ReferenceError(`Hmm... Use of undeclared variable "${varName}"`);
                }

                return safeName;
            }

            let opcode = itemNode.attributes.s.nodeValue;

            switch (opcode) {
                case "reportLessThan":
                    return `(${compileParam(scope, itemNode, 0)} < ${compileParam(scope, itemNode, 1)})`;

                case "reportGreaterThan":
                    return `(${compileParam(scope, itemNode, 0)} > ${compileParam(scope, itemNode, 1)})`;

                case "reportEquals":
                    return `(${compileParam(scope, itemNode, 0)}===${compileParam(scope, itemNode, 1)})`;

                case "reportAnd":
                    return `(${compileParam(scope, itemNode, 0)} && ${compileParam(scope, itemNode, 1)})`;

                case "reportOr":
                    return `(${compileParam(scope, itemNode, 0)} || ${compileParam(scope, itemNode, 1)})`;

                case "reportNot":
                    return `!${compileParam(scope, itemNode, 0)}`;

                case "reportVariadicSum": {
                    // if parameter is a <list>, emit (a + b + c + ..)
                    // instead of env.sum(param)
                    var param = itemNode.firstElementChild;

                    if (param.nodeName === "list") {
                        return `env.sum(${concatList(scope, param, ", ")})`;
                    } else {
                        return `env.sum(...${compileParam(scope, itemNode, 0)})`;
                    }
                }

                case "reportVariadicProduct": {
                    var param = itemNode.firstElementChild;

                    if (param.nodeName === "list") {
                        return `env.product(${concatList(scope, param, ", ")})`;
                    } else {
                        return `env.product(...${compileParam(scope, itemNode, 0)})`
                    }
                }

                case "reportDifference": {
                    return `env.subtract(${compileParam(scope, itemNode, 0)}, ${compileParam(scope, itemNode, 1)})`;
                }

                case "reportQuotient": {
                    return `env.divide(${compileParam(scope, itemNode, 0)}, ${compileParam(scope, itemNode, 1)})`;
                }

                case "reportModulus": {
                    return `(${compileParam(scope, itemNode, 0)} % ${compileParam(scope, itemNode, 1)})`;
                }

                case "reportPower": {
                    return `(${compileParam(scope, itemNode, 0)} ^ ${compileParam(scope, itemNode, 1)})`;
                }

                case "doWaitUntil": {
                    return `do{yield;}while (!${compileParam(scope, itemNode, 0)})`;
                }

                case "doForever": {
                    return `while(true){\n${compileParam(scope, itemNode, 0)}${YIELD_CODE}}`;
                }

                case "doRepeat": {
                    return `for(let i = 0; i < +${compileParam(scope, itemNode, 0)}; i++){\n${compileParam(scope, itemNode, 1)}${YIELD_CODE}}`;
                }

                case "doUntil": {
                    return `while(!${compileParam(scope, itemNode, 0)}){\n${compileParam(scope, itemNode, 1)}${YIELD_CODE}}`;
                }

                case "doIf": {
                    return `if(${compileParam(scope, itemNode, 0)}){\n${compileParam(scope, itemNode, 1)}}`;
                }

                case "doIfElse": {
                    return `if(${compileParam(scope, itemNode, 0)}){\n${compileParam(scope, itemNode, 1)}}else{\n${compileParam(scope, itemNode, 2)}}`;
                }

                case "reportIfElse": {
                    return `${compileParam(scope, itemNode, 0)} ? ${compileParam(scope, itemNode, 1)} : ${compileParam(scope, itemNode, 2)}`;
                }

                case "doFor": {
                    // TODO: for goes backwards when end < start
                    let upvarName = itemNode.children[0].textContent;
                    let start = compileParam(scope, itemNode, 1);
                    let end = compileParam(scope, itemNode, 2);

                    let res = "for (";
                    let safeName = scope.get(upvarName, false);

                    // define variable if not already defined
                    if (safeName) {
                        res += safeName;
                    } else {
                        safeName = scope.addVariable(upvarName);
                        res += `var ${safeName}`;
                    }

                    res += ` = ${start}; ${safeName} <= ${end}; ${safeName}++) {`;
                    let loop = compileParam(scope, itemNode, 3);
                    res += `\n${loop}${YIELD_CODE}}`;

                    return res;
                }

                case "reifyScript":
                case "reifyReporter": {
                    var newScope = new Scope(scope);

                    let paramList = itemNode.children[1];
                    var params = concatList(newScope, paramList, ", ", compileInputName);

                    if (itemNode.children[0].nodeName === "autolambda") {
                        return `function*(${params}){${YIELD_CODE}return ${compileParam(newScope, itemNode, 0)};}`;
                    } else {
                        return `function*(${params}){\n${YIELD_CODE}${compileParam(newScope, itemNode, 0)};}`;
                    }
                }

                case "doRun":
                case "evaluate": {
                    // if arg is a <list>, emit (...)(a, b, c...)
                    // instead of (...).apply(this, args)
                    let target = itemNode.children[0];
                    let args = itemNode.children[1];
                    let post;

                    if (args.nodeName === "list") {
                        post = `(${concatList(scope, args, ", ")})`;
                    } else {
                        post = `.apply(this, ${compileItem(scope, args)})`;
                    }

                    return `yield* (${compileItem(scope, target)})${post}`
                }

                case "fork": {
                    // if arg is a <list>, emit env.fork(f, ...)
                    // instead of env.fork(f, ...(args))
                    let target = itemNode.children[0];
                    let args = itemNode.children[1];
                    let post;

                    if (args.nodeName === "list") {
                        post = `${concatList(scope, args, ", ")}`;
                    } else {
                        post = `...(${compileItem(scope, args)})`;
                    }

                    return `env.fork(${compileItem(scope, target)}, ${post})`
                }

                case "doDeclareVariables": {
                    var listNode = itemNode.children[0];

                    var res = "var ";
                    var items = [...listNode.children];

                    // remove items that are already defined
                    items = items.filter(v => !scope.get(v.textContent, false));

                    if (items.length === 0) return "";

                    // emit variable declarations
                    for (let i = 0; i < items.length; i++) {
                        let v = items[i];

                        res += compileUpvar(scope, v);
                        if (i < items.length - 1) res += ", ";
                    }

                    return res;
                }

                case "doSetVar": {
                    var varName = itemNode.children[0].textContent;
                    var safeName = scope.get(varName);

                    if (!safeName)
                        throw new ReferenceError(`Hmm... Variable "${varName}" does not exist in this context`);

                    return `${safeName} = ${compileParam(scope, itemNode, 1)}`;
                }

                case "doReport": {
                    return `return ${compileParam(scope, itemNode, 0)}`;
                }

                case "doWarp": {
                    return `env.warp(function*(){\n${compileParam(scope, itemNode, 0)};\n})`
                }

                case "reportListAttribute": {
                    var option = compileParam(scope, itemNode, 0);
                    var list = compileParam(scope, itemNode, 1);

                    if (option === "\"length\"") {
                        return `${list}.length`;
                    } else {
                        return `env.listAttrib(${option}, ${list})`;
                    }
                }

                case "doReplaceInList": {
                    var index = compileParam(scope, itemNode, 0);
                    var list = compileParam(scope, itemNode, 1);
                    var value = compileParam(scope, itemNode, 2);

                    return `${list}[${index}-1] = ${value}`;
                }

                case "doAddToList": {
                    return `${compileParam(scope, itemNode, 1)}.push(${compileParam(scope, itemNode, 0)})`;
                }

                case "doDeleteFromList": {
                    return `env.listDelete(${compileParam(scope, itemNode, 1)}, ${compileParam(scope, itemNode, 0)})`;
                }

                case "reportListItem": {
                    var index = compileParam(scope, itemNode, 0);
                    var list = compileParam(scope, itemNode, 1);

                    return `env.listGet(${list}, ${index})`;
                }

                case "reportNewList": {
                    return `[${concatList(scope, itemNode.children[0], ", ")}]`;
                }

                case "reportMonadic": {
                    return `env.ops[${compileParam(scope, itemNode, 0)}](${compileParam(scope, itemNode, 1)})`;
                }

                default: {
                    // don't compile event nodes
                    // (the caller function should account for those)
                    if (EVENT_OPCODES.includes(opcode)) return "";

                    var map = OPCODE_MAPPINGS[opcode];
                    if (!map) {
                        console.warn("Unknown opcode " + opcode);
                    }

                    var res = map + "(";

                    // add parameters
                    let params = itemNode.children;
                    for (let i = 0; i < params.length; i++) {
                        let paramNode = params[i];
                        res += compileItem(scope, paramNode);

                        if (i < params.length - 1) {
                            res += ", ";
                        }
                    }

                    res += ")";

                    return res;
                }
            }

            break;
        }

        case "custom-block": {
            let opcode = itemNode.attributes.s.nodeValue;
            let args = concatList(scope, itemNode, ", ");

            // pass env into function
            // if there are no arguments, don't put a comma
            if (itemNode.firstElementChild) {
                args = "env, " + args;
            } else {
                args = "env";
            }
            return `yield* env.getFunc(\"${opcode}\")(${args})`;
        }
    }
}

const GeneratorFunction = Object.getPrototypeOf(function*(){}).constructor;

function compileDefinition(xml, globalScope) {
    var header = xml.attributes.s.nodeValue;

    // a parameter name in the block header is defined as %'{paramName}'
    // captured name is stored in key #1 of the matchAll return value
    //var paramNamesIt = header.matchAll(/%'([^']*)'/gi);
    var paramTypes = [];
    var paramNames = [];
    var safeParamNames = [];
    var opcodeArr = [];
    var scriptNode;
    //console.log(header.matchAll(/%'([^']*)'/gi));

    for (let node of xml.children) {
        switch (node.nodeName) {
            case "inputs": {
                // get param types
                for (let typeNode of node.children) {
                    paramTypes.push(typeNode.attributes.type.nodeValue);
                }

                break;
            }

            case "script": {
                scriptNode = node;
                break;
            }
        }
    }

    // create function scope
    var scope = new Scope(globalScope);

    // add parameter and create opcode
    let typeIndex = 0;

    for (let word of header.split(" ")) {
        // if this is a parameter name
        if (word[0] === "%") {
            let paramName = word.slice(2, -1);
            let paramType = paramTypes[typeIndex++];

            paramNames.push(paramName);
            safeParamNames.push(scope.addVariable(paramName));
            opcodeArr.push(paramType);
        } else {
            opcodeArr.push(word);
        }
    }

    var opcode = opcodeArr.join(" ");

    console.log(scope);
    console.log(opcode);

    var compiled = `${YIELD_CODE}\n` + compileItem(scope, scriptNode);
    console.log(compiled);

    return {
        func: new GeneratorFunction("env", ...safeParamNames, compiled),
        paramTypes: paramTypes,
        opcode: opcode,
    };
}

function compileScript(xmlRoot, scope) {
    return compileItem(scope, xmlRoot);
}

function getScriptEvent(xmlRoot) {
    var firstChild = xmlRoot.firstChild;
    var opcode = firstChild.attributes.s.nodeValue;
    if (!EVENT_OPCODES.includes(opcode)) return null;

    var res = {};

    switch (opcode) {
        case "receiveGo": {
            res.name = "message";
            res.value = "__shout__go__";
            break;
        }

        case "receiveKey": {
            res.name = "keydown",
            res.value = eval(compileItem(null, firstChild.children[0]));
            break;
        }

        case "receiveMessage": {
            res.name = "message";
            res.value = eval(compileItem(null, firstChild.children[0]));
            break;
        }

        default: {
            console.warn("Unknown event opcode " + opcode);
            res.name = opcode;
        }
    }

    // get parameters
    res.params = [];

    if (firstChild.children[1]) {
        for (let paramNode of firstChild.children[1].children) {
            res.params.push(eval(compileItem(null, paramNode)));
        }
    }

    return res;
}

export { Scope, compileScript, compileDefinition, getScriptEvent }


code:
import { SnapObject } from "./object.js";
import { Color } from "./color.js";

function lerp(s, e, a) {
    return (e - s) * a + s;
}

function getSprite(stage, sprite) {
    if (typeof sprite === "string") {
        return stage.getSprite(sprite);
    }

    return sprite;
}

class Sprite extends SnapObject {
    constructor(stage) {
        super(stage);

        this.varScope.prefix = "env.locals.";
        this.stage = stage;
        this.name = "Sprite";
        this.bubble = null;

        this.x = 0;
        this.y = 0;
        this.scale = 1;
        this.direction = 0;

        this.penSize = 1;
        this.penDown = false; // false
        this.color = new Color(80, 80, 80);

        var sprite = this;

        this.scriptEnv.broadcast = function(msg) {
            sprite.stage.broadcast("message", msg);
        }

        this.scriptEnv.broadcastWait = function*(msg) {
            yield* sprite.stage.broadcastSync(msg);
        }

        this.scriptEnv.penClear = function() {
            sprite.stage.clear();
        }

        this.scriptEnv.sprite = {
            bubble(text) {
                sprite.setBubble(text);
            },

            *sayFor(text, sec) {
                sprite.setBubble(text);
                yield 1000*(+sec);
                sprite.setBubble();
            },

            forward(n) {
                n = +n;
                sprite.x += Math.cos(sprite.direction) * n;
                sprite.y += Math.sin(sprite.direction) * n
            },

            turn(deg) {
                sprite.direction -= +deg / 180 * Math.PI;
            },

            turnLeft(deg) {
                sprite.direction += +deg / 180 * Math.PI;
            },

            setHeading(deg) {
                sprite.direction = -(+deg - 90) / 180 * Math.PI;
            },

            faceTowards(obj) {
                var target = getSprite(sprite.stage, obj);
                sprite.direction = Math.atan2(target.y - sprite.y, target.x - sprite.x);
            },

            goto(obj) {
                if (Array.isArray(obj)) {
                    return sprite.goto(obj[0], obj[1]);
                }

                var other = getSprite(sprite.stage, obj);

                sprite.goto(other.x, other.y);
            },

            gotoXY(x, y) {
                sprite.goto(+x, +y);
            },

            setX(x) {
                sprite.goto(+x, sprite.y);
            },

            setY(y) {
                sprite.goto(sprite.x, +y);
            },

            changeX(dx) {
                sprite.goto(sprite.x + +dx, sprite.y);
            },

            changeY(dy) {
                sprite.goto(sprite.x, sprite.y + +dy);
            },

            *glide(t, x, y) {
                t = +t;
                x = +x;
                y = +y;

                var startX = sprite.x;
                var startY = sprite.y;
                var elapsed = 0;

                while (elapsed < t) {
                    let a = elapsed / t;
                    sprite.goto(lerp(startX, x, a), lerp(startY, y, a));
                    elapsed += yield 0;
                }

                sprite.goto(x, y);
            },

            setScale(n) {
                sprite.scale = +n / 100;
            },

            changeScale(n) {
                sprite.scale += +n / 100;
            },

            getScale() {
                return sprite.scale * 100;
            },

            penDown() {
                sprite.penDown = true;
            },

            penUp() {
                sprite.penDown = false;
            },

            setPenSize(n) {
                sprite.penSize = +n;
            },
        }
    }

    async loadXml(xml) {
        if (xml.nodeName !== "sprite") throw new Error("Expected <sprite> tag");
        await super.loadXml(xml);

        var attrib = (n) => xml.attributes[n].nodeValue;

        this.x = attrib("x");
        this.y = attrib("y");
        this.direction = -(attrib("heading") - 90) / 180 * Math.PI;
    }

    getProject() {
        return this.stage.getProject();
    }

    get scene() {
        return this.stage.scene;
    }

    setBubble(msg) {
        console.log(this.name + " says", msg);
        this.bubble = msg;
    }

    goto(x, y) {
        if (this.penDown) {
            this.stage.drawLine(this.x, this.y, x, y, this.color, this.penSize);
        }

        this.x = x;
        this.y = y;
    }

    render(canvas, ctx) {
        if (!this.shown) return;

        ctx.fillStyle = "black";

        ctx.save();
        ctx.translate(this.x, -this.y);
        ctx.rotate(this.direction);
        this.applyEffects(ctx);

        if (this.curCostume) {
            ctx.scale(this.scale, this.scale);
            ctx.drawImage(this.curCostume.canvas, this.curCostume.width / -2, this.curCostume.height / -2);
        } else {
            ctx.fillStyle = this.color.toRGBString();

            // draw and fill turtle shape
            ctx.beginPath();
            ctx.moveTo(0, 0);
            ctx.lineTo(-40 * this.scale, -10 * this.scale);
            ctx.lineTo(-30 * this.scale, 0);
            ctx.lineTo(-40 * this.scale, 10 * this.scale);
            ctx.lineTo(0, 0);
            ctx.fill();

            // draw inner darker outline
            ctx.lineWidth = 2;
            ctx.strokeStyle = "rgba(0, 0, 0, 0.5)";
            ctx.stroke();

            // draw white outline
            ctx.lineWidth = 1;
            ctx.strokeStyle = "white";
            ctx.stroke();

            ctx.closePath();
        }

        ctx.restore();
    }
 }

 export { Sprite }


code:
import { SnapObject } from "./object.js";
import { Sprite } from "./sprite.js";

class Stage extends SnapObject {
    constructor(scene) {
        super(scene);

        this.name = "Stage";
        this.scene = scene;

        this.sprites = [];

        this.width = 480;
        this.height = 360;

        this.trails = document.createElement("canvas");
        this.trailsCtx = this.trails.getContext("2d");
        this.trails.width = this.width;
        this.trails.height = this.height;

        var self = this;
        this.scriptEnv.globals = scene.variables;

        this.scriptEnv.broadcast = function(msg) {
            self.broadcast("message", msg);
        }

        this.scriptEnv.broadcastWait = function*(msg) {
            yield* self.broadcastSync("message", msg);
        }

        this.scriptEnv.penClear = function() {
            self.clear();
        }
    }

    async loadXml(xml) {
        if (xml.nodeName !== "stage") throw new Error("Expected <stage> tag");
        await super.loadXml(xml);

        // store temporary sprites list
        // this will then be sorted by sprite's idx attribute
        var sprites = [];

        for (let child of xml.children) {
            switch (child.nodeName) {
                case "sprites": {
                    for (let spriteNode of child.children) {
                        if (spriteNode.nodeName === "sprite") {
                            var sprite = new Sprite(this);
                            sprite.loadXml(spriteNode);
                            sprites.push([sprite, +spriteNode.attributes.idx.nodeValue]);
                        }
                    }

                    break;
                }
            }
        }

        sprites.sort((a, b) => a[1] - b[1]);
        this.sprites = sprites.map(v => v[0]);
    }

    setSize(w, h) {
        this.width = w;
        this.height = h;

        this.trails.width = w;
        this.trails.height = h;
    }

    clear() {
        var canvas = this.trails;
        var ctx = this.trailsCtx;

        ctx.clearRect(0, 0, this.width, this.height);
    }

    drawLine(x0, y0, x1, y1, color, size) {
        // don't draw line if start and end pos are the same
        if (x0 === x1 && y0 === y1) return;

        var ctx = this.trailsCtx;

        ctx.strokeStyle = color.toRGBString();
        ctx.lineWidth = size;
        ctx.lineCap = "round";

        ctx.beginPath();
        ctx.moveTo(x0 + this.width / 2, -y0 + this.height / 2);
        ctx.lineTo(x1 + this.width / 2, -y1 + this.height / 2);
        ctx.stroke();
        ctx.closePath();
    }

    getProject() {
        return this.scene.project;
    }

    getSprite(name) {
        this.sprites.find(v => v.name === name);
    }

    broadcast(type, name, ...args) {
        this.fireEvent(type, name, ...args);

        for (let sprite of this.sprites) {
            sprite.fireEvent(type, name, ...args);
        }
    }

    *broadcastSync(type, name) {
        yield* this.fireEventSync(type, name);

        for (let sprite of this.sprites) {
            yield* sprite.fireEventSync(type, name);
        }
    }

    render(canvas, ctx) {
        if (!this.shown) return;

        ctx.fillStyle = "white";
        ctx.fillRect(0, 0, canvas.width, canvas.height);

        ctx.save();

        this.applyEffects(ctx);

        if (this.curCostume) {
            ctx.drawImage(this.curCostume.canvas, this.width / 2 - this.curCostume.width / 2, this.height / 2 - this.curCostume.height / 2);
        }

        ctx.drawImage(this.trails, 0, 0);

        ctx.translate(this.width / 2, this.height / 2);

        for (let sprite of this.sprites) {
            sprite.render(canvas, ctx);
        }

        ctx.restore();
    }
}

export { Stage }


code:
/build/
/install/
/release/
/sources/
/libreboot.conf
.version
.revision
.tarfiles
.epoch
push
*.vim
/TODO/
/docs/version
/bucts/
/coreboot/
/crossgcc/
/flashrom/
/grub/
/memtest86plus/
/seabios/
/bin/
/resources/utilities/ich9deblob/*.rom
/resources/utilities/ich9deblob/*.bin
/resources/utilities/ich9deblob/ich9deblob
/resources/utilities/ich9deblob/ich9gen
/resources/utilities/ich9deblob/demefactory
/resources/utilities/ich9deblob/obj/*.o
/resources/utilities/ich9deblob/obj/*/*.o
/resources/utilities/ich9deblob/mkdescriptor*.[ch]
/resources/utilities/ich9deblob/mkgbe*.[ch]
/resources/utilities/grub-assemble/grub_*.elf
/mkgbe.[ch]
/*.bin
/resources/utilities/i945-pwm/i945-pwm
/push
/ChangeLog
/NEWS
/version
/versiondate
/gm45macaddress
tocheck*
*.html
!www/template.html
/www/news/index.md
/www/feed.xml
/www/news/feed.xml

path: .gitignore

license: mit


code:
Paper Build System
==================

Entry Point
-----------

The entry point for using the paper build system is the main script in the root
directory, named after the build system (paper, libreboot, etc).
Running the main script with no argument will show its general usage.

Configuration
-------------

The paper build system can be configured with a script named after the build
system (paper, libreboot, etc) with a ".conf" suffix. It is automatically loaded
by the build system when running the main script.

It contains environment variables assigned to the desired values. The list of
environment variables is shown in the main script's general usage.

Project and Tool Targets
------------------------

The build system works around the concepts of projects and tools, that define
specific components that can be used to produce either:
* sources
* systems
* images
* tools

Various actions are available for each project and tool targets, many of which
are shown in the main script's general usage. Each project and tool may provide
a usage action that allows to see the specific usage for it. Actions are
executed recursively when no targets are specified.

Each project and tool target has its own directory (either in projects or tools)
that contain a script named after the target and possible a helper script, named
after the script with a "-helper" suffix. The helper script is automatically
included by the build system. Functions in helper scripts are usually prefixed
with the name of the target, where "-" symbols are replaced with "_" symbols.

Each project and tool target's actions are functions defined in the target's
specific script, with names matching the target's actions.

Meta-Targets
------------

Meta targets are project and tool targets that apply the requested action to
individual targets, allowing to execute an action to many targets at once.
For instance, a meta-target named after the build system with a "-all" suffix
would call other meta-targets, prefixed with "-images", "-tools", etc that would
then perform the requested action to all underlying targets.

Projects Actions
----------------

Various generic actions allow preparing projects through a series of steps:
* downloading, extracting or updating the project's sources
* building the project to a build directory
* installing the project to an install directory
* releasing the project to a release directory
* cleaning the build, install and release directories

Actions can be checked by a matching project-specific function, named after the
function to check with a "_check" suffix, to determine whether it is necessary
to run them again to follow the steps. An environment variable can force actions
to be executed, by specifying a space-separated list of projects:
PROJECTS_FORCE.

Projects Configuration and Patches
----------------------------------

Configuration for each project is stored in each project's own directory.
Targets for each project are defined with a "targets" file in each directory
of the "configs" directory. Targets are read recursively, following
sub-directory names for project targets.

Each project's configuration directory can be used to hold target-specific
information and configuration.

An "install" file in each sub-directory indicated which files to grab from the
build files and where to install them in the install directory.

Projects Sources
----------------

Each project can either download specific sources or use another project's
sources, possibly providing its own revision and patches.

Sources are downloaded with the "download" action or can be extracted from
released sources (after placing the sources in the sources directory) with the
"extract" action.

Projects may also keep their sources in a "sources" directory in their
project-specific directory.

Projects Build
--------------

Each project is built to a build directory, named after the project, with the
list of targets separated by a "-" symbol.

An environment variable allows controlling the number of tasks to run at the
same time: TASKS.

Projects Install
----------------

Projects are installed from "install" files in the project directory, that
copies the selected built files to the install directory, named after the
project, with the list of targets separated by a "-" symbol. These install files
are read recursively, following sub-directory names for project targets.

Additional files to install can be specified in the "install" directory and
described in an "install" file. These install files are read recursively,
following sub-directory names for project targets.

Projects Release
----------------

Projects are released to a release directory, named after the project, with the
list of targets separated by a "-" symbol. Each project's install files are
packed into a tarball to the corresponding release directory. A checksum and a
GPG detached signature (if the RELEASE_KEY environment variable is set) are also
generated.

Tarballs are generated reproducibly, from a list of files stored in the
".tarfiles" file. They may also contain the ".epoch", git ".revision" and
".version" files.

Tools Actions
-------------

Tools are used for maintaining the build system, for performing routine tasks
that can be automated. They may have specific actions and not implement any of
the generic actions.

Actions can be checked by a matching tool-specific function, named after the
function to check with a "_check" suffix, to determine whether it is necessary
to run them again to follow the steps. An environment variable can force actions
to be executed, by specifying a space-separated list of tasks: TASKS_FORCE.

Tools Sources
-------------

Tools may keep their sources in a "sources" directory in their tool-specific
directory. These sources may be updated with the "update" action.