diff --git a/SCALE_DOCS.md b/SCALE_DOCS.md
deleted file mode 100644
index 92d4dfc..0000000
--- a/SCALE_DOCS.md
+++ /dev/null
@@ -1,298 +0,0 @@
-# Scale Docs
-
-Everything you need to get started with using [Scale](https://github.com/DragonRidersUnite/scale).
-
-[Check out the CHANGELOG for the summary of recent changes!](https://github.com/DragonRidersUnite/scale/wiki/CHANGELOG)
-
-## Quickstart
-
-Once you've got your game from the Scale template dropped into your `mygame` directory in your DragonRuby GTK game, here's what you'll want to do next.
-
-### Configure
-
-Start by specifying your name and game title in `metadata/game_metadata.txt`. The following properties are useful:
-
-- `devid` — your itch.io username, no spaces
-- `devtitle` — your name, spaces are okay
-- `gameid` — the URL slug of your game on itch.io that you must already create, no spaces
-- `gametitle` — the name of your game, spaces are okay!
-
-Now when you start the DragonRuby engine for your game, you'll see what you've set.
-
-### Lay of the Land
-
-Because all of Scale is included with your new game, you can just browse through the source code to get the lay of the land. You'll notice in the `app/` directory a bunch of files! It's okay, don't worry. It's pretty sensibly organized, and there are plenty of comments.
-
-Explore, be curious, and change things to suit your needs.
-
-Scale is structured to follow the default DragonRuby GTK way of working with methods and `args.state`. That drives how much of it works. Most of Scale is organized into modules so that there aren't method name conflicts in the global space.
-
-### Gameplay
-
-Open up `app/scenes/gameplay.rb`, as that's where you'll actually add the fun parts of your game. `Scene.tick_gameplay` is just like the regular ole `#tick` in DragonRuby GTK. It takes args, and you go from there. It does include some handy stuff though, but just let that be.
-
-You'll code your game just as you normally would. If you're new to DragonRuby GTK, [check out the book](https://book.dragonriders.community/) to get started.
-
-### Input
-
-Scale comes with some helper methods to make checking for input from multiple sources (multiple keyboard keys and gamepad buttons) easy. That code lives in `app/input.rb`, and out of the box, you get:
-
-- `primary_down?` — check if J, Z, Space, or Gamepad A button was just pressed
-- `primary_down_or_held?` — check if J, Z, Space, or Gamepad A button was just pressed or is being held
-- `secondary_down?` — check if K, X, Backspace, or Gamepad B button was just pressed
-- `secondary_down_or_held?` — check if K, X, Backspace, or Gamepad B button was just pressed or is being held
-- `pause_down?` — check if Escape, P, or Gamepad Start button was just pressed, which pauses the game
-
-You could add more methods for various inputs in your game. Maybe there's a secondary button you use. Or any number of them! These input methods make it really easy to support various input methods without worrying about the keys/buttons that are being pressed. Want to add a new key for a given layout? Just change it.
-
-Here's an example of how you'd use it if you wanted to have your player swing their sword:
-
-``` ruby
-if primary_down?(args.inputs)
- swing_sword(args, args.state.player)
-end
-```
-
-### Text
-
-You'll very likely need to display text in your game to show health or the player's level or to give instruction. It's a fundamental part of game user interfaces. `app/text.rb` contains a few helpful constructs to make working with text easier.
-
-First is the `TEXT` Hash constant. It contains key values of the text to display in your game. This is preferable to putting strings everywhere because you can more easily review the text for typos and eventually translate your game much more easily. It takes a little time to get used to putting your text here first, but it'll become second nature quick enough. You'll see text for what already exists in Scale.
-
-`#text` is a method you call to access the values in `TEXT`. Example:
-
-``` ruby
-text(:start)
-```
-
-returns `"Start"`.
-
-Then we've got the `#label` method. It contains sensible defaults for outputting labels quickly with DragonRuby GTK. It's got a friendlier API than the default data structure in DRGTK. There are multiple ways to use it.
-
-In its simplest form, you can pass in a symbol key for `TEXT` and specify the position to render it:
-
-``` ruby
-args.outputs.labels << label(:start, x: 100, y: 100)
-```
-
-You can also pass in a value, like a number that will display:
-
-``` ruby
-args.outputs.labels << label(args.state.player.level, x: 100, y: 100)
-```
-
-Additional parameters are supported too, all the way up to something like this:
-
-``` ruby
-args.outputs.labels << label(
- :restart, x: 100, y: 100, align: ALIGN_CENTER,
- size: SIZE_SM, color: RED, font: FONT_ITALIC
-)
-```
-
-In `app/text.rb` you'll find the constants for text size and the various fonts. Change them as you'd like!
-
-### Sprites
-
-A lot of games need sprites, and when making them, it's so helpful to see them in the context of your game. DragonRuby GTK allows you to reload sprites in your game, but you need to specify which ones to reload. To get around this, in Scale you track your sprites in `app/sprite.rb`'s `SPRITES` hash. It's a little tedious, but by having a dictionary of sprites, they can easily be reloaded with i when developing your game.
-
-Get the path for your sprite with `Sprite.for(:key)`:
-
-``` ruby
-args.outputs.sprites << {
- x: 100, y: 100, w: 32, h: 32, path: Sprite.for(:player),
-}
-```
-
-### Scenes
-
-The `app/scenes/` directory is where different scenes of your game go. There are scenes for Paused, Main Menu, Settings, and Gameplay. Scale uses `args.state.scene` to know which scene the game is in.
-
-You can switch scenes by using `Scene.switch(args, :gameplay)` where the parameter is the symbol of the scene you want. It must match the name of your scene method after the `tick_` prefix. So if you wanted a `:credits` scene, you'd define it like this in `app/scenes/credits.rb`:
-
-``` ruby
-module Scene
- class << self
- def tick_credits(args)
- args.outputs.labels << label(:credits, x: args.grid.w / 2, y: args.grid.top - 200, align: ALIGN_CENTER, size: SIZE_LG, font: FONT_BOLD)
- end
- end
-end
-```
-
-(Don't forget to require it in `app/main.rb` too!)
-
-Then when you want to show the Credits scene, call `Scene.switch(args, :credits)`.
-
-### Collision Detection
-
-Scale provides you with a collision method that executes the passed in block for each element that intersects:
-
-``` ruby
-collide(tiles, bullets) do |tile, bullet|
- bullet.dead = true
-end
-```
-
-It takes arrays or single objects as parameters.
-
-### Menus
-
-You'll find examples of menus throughout the Scale codebase for common scenes like Settings and the Main Menu.
-
-Menus support cursor-based navigation or buttons for mouse/touch.
-
-How they work is pretty simple, you just call `Menu.tick` and pass in an array of menu options.
-
-``` ruby
-options = [
- {
- key: :attack,
- on_select: -> (args) do
- # do the attack
- end
- },
- {
- key: :defend,
- on_select: -> (args) do
- # defend
- end
- },
-]
-Menu.tick(args, :your_menu_name, options)
-```
-
-The options array is just a collection of hashes with a key and an `on_select` lambda that gets called with `args` for doing anything in your game that you need to have happen.
-
-`Menu.tick` also supports an optional `menu_y` for positioning the menu.
-
-### Colors
-
-A simple color palette is provided in `app/constants.rb`. Most of the primary colors are present, along with some variants. They return Hashes with `r`, `g`, and `b` keys. If you have a sprite that you want to change red, you'd do this:
-
-``` ruby
-args.outputs.sprites << {
- x: 100, y: 100, w: 32, h: 32, path: Sprite.for(:player)
-}.merge(RED)
-```
-
-### Sound Effects & Music
-
-Scale comes with a few helper methods to make playing music and sound effects easy, as well as settings to enable or disable their playback.
-
-Play a sound effect:
-
-``` ruby
-play_sfx(args, :enemy_hit)
-```
-
-the symbol (or string) file key for the file must correspond to the file's name in `sounds/`.
-
-Here's how to play music:
-
-``` ruby
-play_music(args, :menu)
-```
-
-the symbol (or string) file key for the file must correspond to the file's name in `sounds/`.
-
-You can pause and resume music easily with:
-
-``` ruby
-pause_music(args)
-resume_music(args)
-```
-
-Scale assumes only one music track can be playing at a time.
-
-### Adding New Files
-
-When you add new code files to `app/`, just be sure to require them in `app/main.rb`.
-
-### Debug Tick & Development Shortcuts
-
-When you're making a game, you often want to have easy shortcuts to toggle settings. Maybe you want to make your player invincible so you can easily test changes out. `app/tick.rb` contains a method called `#debug_tick` that's only called when you're game is in debug mode (a.k.a. not the version shipped to players). Anything you put in there will run every tick but only while you make the game.
-
-You'll see there are already three shortcuts Scale gives you:
-
-- i — reloads sprites from disk
-- r — resets game state
-- 0 — displays framerate and other debug details
-
-Use those as templates to add your own development shortcuts.
-
-You can check for Debug mode in your game anywhere with the `debug?` method.
-
-### `#debug_label` Method
-
-It's common to need to display debug-only information about entities in your game. Maybe you want to see a value that changes over time. This is what `#debug_label` is for. It putputs text that's shown when you toggle on debug details with the 0 key.
-
-Here's an example of how to use it to track the player's current coordinates:
-
-``` ruby
-# assume we have args.state.player that can move
-player = args.state.player
-debug_label(args, player.x, player.y - 4, "#{player.x}, #{player.y}")
-```
-
-### Tests
-
-The `test/tests.rb` is where you can put tests for your game. It also includes tests for methods provided by Scale. Tests are powered by [DragonTest](https://github.com/DragonRidersUnite/dragon_test), a simple testing library for DragonRuby GTK. You'll see plenty of examples in there, but here's a quick overview:
-
-Write tests:
-
-``` ruby
-test :text_for_setting_val do |args, assert|
- it "returns proper text for boolean vals" do
- assert.equal!(text_for_setting_val(true), "ON")
- assert.equal!(text_for_setting_val(false), "OFF")
- end
-
- it "passes the value through when not a boolean" do
- assert.equal!(text_for_setting_val("other"), "other")
- end
-end
-```
-
-You've got these assertions:
-
-- `assert.true!` - whether or not what's passed in is truthy, ex: `assert.true!(5 + 5 == 10)`
-- `assert.false!` - whether or not what's passed in is falsey, ex: `assert.false!(5 + 5 != 10)`
-- `assert.equal!` - whether or not what's passed into param 1 is equal to param 2, ex: `assert.equal!(5, 2 + 3)`
-- `assert.exception!` - expect the called code to raise an error with optional message, ex: `assert.exception!(KeyError, "Key not found: :not_present") { text(args, :not_present) }`
-- `assert.includes!` - whether or not the array includes the value, ex: `assert.includes!([1, 2, 3], 2)`
-
-Run your tests with: `./run_tests` — test runner script for Unix-like environments with a shell that has proper exit codes on success and fail
-
-Your tests will also run when you save test files and be output to your running game's logs. Nifty!
-
-## Debug Shortcuts
-
-You'll find these in the README, too. Scale comes with some handy keyboard shortcuts that only run in debug mode to make building your game easier.
-
-- 0 — display debug details (ex: framerate)
-- i — reload sprites from disk
-- r — reset the entire game state
-- m — toggle mobile simulation
-
-## Mobile Development
-
-Use the `#mobile?` method to check to add logic specifically for mobile devices. Press m to simulate this on desktop so you can easily check how your game will look on those platforms.
-
-Example:
-
-``` ruby
-text_key = mobile? ? :instructions_mobile : :instructions
-```
-
-There are convenient methods and tracking for swipe inputs on touch devices. Scale automatically keeps track of them, and if you use the `up?(args)`, `down?(args)`, `left?(args)`, `right?(args)` methods, they're automatically checked. Otherwise, you can check to see if a swipe occurred with:
-
-``` ruby
-if args.state.swipe.up
- # do the thing
-end
-```
-
-## Make Scale Yours!
-
-This is your game now. Scale is just here to help you out. Change Scale to meet your game's needs.
diff --git a/installer/.vs/installer/v17/.suo b/installer/.vs/installer/v17/.suo
new file mode 100644
index 0000000..fc0afe4
Binary files /dev/null and b/installer/.vs/installer/v17/.suo differ
diff --git a/installer/installer copy.vdproj b/installer/installer copy.vdproj
new file mode 100644
index 0000000..40030a3
--- /dev/null
+++ b/installer/installer copy.vdproj
@@ -0,0 +1,761 @@
+"DeployProject"
+{
+"VSVersion" = "3:800"
+"ProjectType" = "8:{978C614F-708E-4E1A-B201-565925725DBA}"
+"IsWebType" = "8:FALSE"
+"ProjectName" = "8:installer"
+"LanguageId" = "3:1033"
+"CodePage" = "3:1252"
+"UILanguageId" = "3:1033"
+"SccProjectName" = "8:"
+"SccLocalPath" = "8:"
+"SccAuxPath" = "8:"
+"SccProvider" = "8:"
+ "Hierarchy"
+ {
+ "Entry"
+ {
+ "MsmKey" = "8:_8B48DC19D11942ABBE0C7A1402172A07"
+ "OwnerKey" = "8:_UNDEFINED"
+ "MsmSig" = "8:_UNDEFINED"
+ }
+ "Entry"
+ {
+ "MsmKey" = "8:_CB44E61B41964776BF2E52F12480675E"
+ "OwnerKey" = "8:_UNDEFINED"
+ "MsmSig" = "8:_UNDEFINED"
+ }
+ }
+ "Configurations"
+ {
+ "Debug"
+ {
+ "DisplayName" = "8:Debug"
+ "IsDebugOnly" = "11:TRUE"
+ "IsReleaseOnly" = "11:FALSE"
+ "OutputFilename" = "8:Debug\\installer.msi"
+ "PackageFilesAs" = "3:2"
+ "PackageFileSize" = "3:-2147483648"
+ "CabType" = "3:1"
+ "Compression" = "3:2"
+ "SignOutput" = "11:FALSE"
+ "CertificateFile" = "8:"
+ "PrivateKeyFile" = "8:"
+ "TimeStampServer" = "8:"
+ "InstallerBootstrapper" = "3:2"
+ "BootstrapperCfg:{63ACBE69-63AA-4F98-B2B6-99F9E24495F2}"
+ {
+ "Enabled" = "11:TRUE"
+ "PromptEnabled" = "11:TRUE"
+ "PrerequisitesLocation" = "2:1"
+ "Url" = "8:"
+ "ComponentsUrl" = "8:"
+ "Items"
+ {
+ "{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:.NETFramework,Version=v4.7.2"
+ {
+ "Name" = "8:Microsoft .NET Framework 4.7.2 (x86 and x64)"
+ "ProductCode" = "8:.NETFramework,Version=v4.7.2"
+ }
+ }
+ }
+ }
+ "Release"
+ {
+ "DisplayName" = "8:Release"
+ "IsDebugOnly" = "11:FALSE"
+ "IsReleaseOnly" = "11:TRUE"
+ "OutputFilename" = "8:..\\..\\builds\\cube-tube-installer-x64.msi"
+ "PackageFilesAs" = "3:2"
+ "PackageFileSize" = "3:-2147483648"
+ "CabType" = "3:1"
+ "Compression" = "3:2"
+ "SignOutput" = "11:FALSE"
+ "CertificateFile" = "8:"
+ "PrivateKeyFile" = "8:"
+ "TimeStampServer" = "8:"
+ "InstallerBootstrapper" = "3:2"
+ "BootstrapperCfg:{63ACBE69-63AA-4F98-B2B6-99F9E24495F2}"
+ {
+ "Enabled" = "11:TRUE"
+ "PromptEnabled" = "11:TRUE"
+ "PrerequisitesLocation" = "2:1"
+ "Url" = "8:"
+ "ComponentsUrl" = "8:"
+ "Items"
+ {
+ "{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:.NETFramework,Version=v4.7.2"
+ {
+ "Name" = "8:Microsoft .NET Framework 4.7.2 (x86 and x64)"
+ "ProductCode" = "8:.NETFramework,Version=v4.7.2"
+ }
+ }
+ }
+ }
+ }
+ "Deployable"
+ {
+ "CustomAction"
+ {
+ }
+ "DefaultFeature"
+ {
+ "Name" = "8:DefaultFeature"
+ "Title" = "8:"
+ "Description" = "8:"
+ }
+ "ExternalPersistence"
+ {
+ "LaunchCondition"
+ {
+ }
+ }
+ "File"
+ {
+ "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8B48DC19D11942ABBE0C7A1402172A07"
+ {
+ "SourcePath" = "8:..\\..\\builds\\cube-tube-windows-amd64.exe"
+ "TargetName" = "8:cube-tube-windows-amd64.exe"
+ "Tag" = "8:"
+ "Folder" = "8:_FE392AC6266F40A5BA12C30DB5516B78"
+ "Condition" = "8:"
+ "Transitive" = "11:FALSE"
+ "Vital" = "11:TRUE"
+ "ReadOnly" = "11:FALSE"
+ "Hidden" = "11:FALSE"
+ "System" = "11:FALSE"
+ "Permanent" = "11:FALSE"
+ "SharedLegacy" = "11:FALSE"
+ "PackageAs" = "3:1"
+ "Register" = "3:1"
+ "Exclude" = "11:FALSE"
+ "IsDependency" = "11:FALSE"
+ "IsolateTo" = "8:"
+ }
+ "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_CB44E61B41964776BF2E52F12480675E"
+ {
+ "SourcePath" = "8:..\\metadata\\icon.ico"
+ "TargetName" = "8:icon.ico"
+ "Tag" = "8:"
+ "Folder" = "8:_FE392AC6266F40A5BA12C30DB5516B78"
+ "Condition" = "8:"
+ "Transitive" = "11:FALSE"
+ "Vital" = "11:TRUE"
+ "ReadOnly" = "11:FALSE"
+ "Hidden" = "11:FALSE"
+ "System" = "11:FALSE"
+ "Permanent" = "11:FALSE"
+ "SharedLegacy" = "11:FALSE"
+ "PackageAs" = "3:1"
+ "Register" = "3:1"
+ "Exclude" = "11:FALSE"
+ "IsDependency" = "11:FALSE"
+ "IsolateTo" = "8:"
+ }
+ }
+ "FileType"
+ {
+ }
+ "Folder"
+ {
+ "{1525181F-901A-416C-8A58-119130FE478E}:_8C52B4D6CA19438E912584BB847A88C4"
+ {
+ "Name" = "8:#1916"
+ "AlwaysCreate" = "11:FALSE"
+ "Condition" = "8:"
+ "Transitive" = "11:FALSE"
+ "Property" = "8:DesktopFolder"
+ "Folders"
+ {
+ }
+ }
+ "{1525181F-901A-416C-8A58-119130FE478E}:_D5392E2DA1B749BB891650F30892B215"
+ {
+ "Name" = "8:#1919"
+ "AlwaysCreate" = "11:FALSE"
+ "Condition" = "8:"
+ "Transitive" = "11:FALSE"
+ "Property" = "8:ProgramMenuFolder"
+ "Folders"
+ {
+ }
+ }
+ "{3C67513D-01DD-4637-8A68-80971EB9504F}:_FE392AC6266F40A5BA12C30DB5516B78"
+ {
+ "DefaultLocation" = "8:[ProgramFiles64Folder][Manufacturer]\\[ProductName]"
+ "Name" = "8:#1925"
+ "AlwaysCreate" = "11:FALSE"
+ "Condition" = "8:"
+ "Transitive" = "11:FALSE"
+ "Property" = "8:TARGETDIR"
+ "Folders"
+ {
+ }
+ }
+ }
+ "LaunchCondition"
+ {
+ }
+ "Locator"
+ {
+ }
+ "MsiBootstrapper"
+ {
+ "LangId" = "3:1033"
+ "RequiresElevation" = "11:FALSE"
+ }
+ "Product"
+ {
+ "Name" = "8:Microsoft Visual Studio"
+ "ProductName" = "8:Cube Tube"
+ "ProductCode" = "8:{14680FA0-682D-4989-93C8-340FF279BB92}"
+ "PackageCode" = "8:{0FC6B770-DCA1-431F-AF4F-25736D372F47}"
+ "UpgradeCode" = "8:{CD4947B5-EF08-4530-A370-44E0B5F6F762}"
+ "AspNetVersion" = "8:4.0.30319.0"
+ "RestartWWWService" = "11:FALSE"
+ "RemovePreviousVersions" = "11:FALSE"
+ "DetectNewerInstalledVersion" = "11:TRUE"
+ "InstallAllUsers" = "11:FALSE"
+ "ProductVersion" = "8:0.1.1"
+ "Manufacturer" = "8:death.au"
+ "ARPHELPTELEPHONE" = "8:"
+ "ARPHELPLINK" = "8:"
+ "Title" = "8:Cube Tube Installer"
+ "Subject" = "8:"
+ "ARPCONTACT" = "8:death.au"
+ "Keywords" = "8:"
+ "ARPCOMMENTS" = "8:Cube Tube"
+ "ARPURLINFOABOUT" = "8:"
+ "ARPPRODUCTICON" = "8:_CB44E61B41964776BF2E52F12480675E"
+ "ARPIconIndex" = "3:0"
+ "SearchPath" = "8:"
+ "UseSystemSearchPath" = "11:TRUE"
+ "TargetPlatform" = "3:1"
+ "PreBuildEvent" = "8:"
+ "PostBuildEvent" = "8:"
+ "RunPostBuildEvent" = "3:0"
+ }
+ "Registry"
+ {
+ "HKLM"
+ {
+ "Keys"
+ {
+ "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_638ADCEBDB6040CA9692564EBAED209F"
+ {
+ "Name" = "8:Software"
+ "Condition" = "8:"
+ "AlwaysCreate" = "11:FALSE"
+ "DeleteAtUninstall" = "11:FALSE"
+ "Transitive" = "11:FALSE"
+ "Keys"
+ {
+ "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_CB383D135A0F41D49F1166D62F4E5B42"
+ {
+ "Name" = "8:[Manufacturer]"
+ "Condition" = "8:"
+ "AlwaysCreate" = "11:FALSE"
+ "DeleteAtUninstall" = "11:FALSE"
+ "Transitive" = "11:FALSE"
+ "Keys"
+ {
+ }
+ "Values"
+ {
+ }
+ }
+ }
+ "Values"
+ {
+ }
+ }
+ }
+ }
+ "HKCU"
+ {
+ "Keys"
+ {
+ "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_767D271A073F46F9BEF8F71A71AB3646"
+ {
+ "Name" = "8:Software"
+ "Condition" = "8:"
+ "AlwaysCreate" = "11:FALSE"
+ "DeleteAtUninstall" = "11:FALSE"
+ "Transitive" = "11:FALSE"
+ "Keys"
+ {
+ "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_3E2EF3C2D47640F9ACAA54251E50687D"
+ {
+ "Name" = "8:[Manufacturer]"
+ "Condition" = "8:"
+ "AlwaysCreate" = "11:FALSE"
+ "DeleteAtUninstall" = "11:FALSE"
+ "Transitive" = "11:FALSE"
+ "Keys"
+ {
+ }
+ "Values"
+ {
+ }
+ }
+ }
+ "Values"
+ {
+ }
+ }
+ }
+ }
+ "HKCR"
+ {
+ "Keys"
+ {
+ }
+ }
+ "HKU"
+ {
+ "Keys"
+ {
+ }
+ }
+ "HKPU"
+ {
+ "Keys"
+ {
+ }
+ }
+ }
+ "Sequences"
+ {
+ }
+ "Shortcut"
+ {
+ "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_96806951FD8247D18ACFDD28CF13DC84"
+ {
+ "Name" = "8:Cube Tube"
+ "Arguments" = "8:"
+ "Description" = "8:"
+ "ShowCmd" = "3:1"
+ "IconIndex" = "3:0"
+ "Transitive" = "11:FALSE"
+ "Target" = "8:_8B48DC19D11942ABBE0C7A1402172A07"
+ "Folder" = "8:_8C52B4D6CA19438E912584BB847A88C4"
+ "WorkingFolder" = "8:_FE392AC6266F40A5BA12C30DB5516B78"
+ "Icon" = "8:_CB44E61B41964776BF2E52F12480675E"
+ "Feature" = "8:"
+ }
+ "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_FA3A6FA4ADF5411AA1478FE09BD4C499"
+ {
+ "Name" = "8:Cube Tube"
+ "Arguments" = "8:"
+ "Description" = "8:"
+ "ShowCmd" = "3:1"
+ "IconIndex" = "3:0"
+ "Transitive" = "11:FALSE"
+ "Target" = "8:_8B48DC19D11942ABBE0C7A1402172A07"
+ "Folder" = "8:_D5392E2DA1B749BB891650F30892B215"
+ "WorkingFolder" = "8:_FE392AC6266F40A5BA12C30DB5516B78"
+ "Icon" = "8:_CB44E61B41964776BF2E52F12480675E"
+ "Feature" = "8:"
+ }
+ }
+ "UserInterface"
+ {
+ "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_098F2EE2CAEE410195CE081E2FAF5FE2"
+ {
+ "Name" = "8:#1900"
+ "Sequence" = "3:2"
+ "Attributes" = "3:1"
+ "Dialogs"
+ {
+ "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_5E2C5A84F47F4319A72E9410D94EE847"
+ {
+ "Sequence" = "3:200"
+ "DisplayName" = "8:Installation Folder"
+ "UseDynamicProperties" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdAdminFolderDlg.wid"
+ "Properties"
+ {
+ "BannerBitmap"
+ {
+ "Name" = "8:BannerBitmap"
+ "DisplayName" = "8:#1001"
+ "Description" = "8:#1101"
+ "Type" = "3:8"
+ "ContextData" = "8:Bitmap"
+ "Attributes" = "3:4"
+ "Setting" = "3:1"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ }
+ }
+ "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_7143F0C480E346A38A0310E2734D9A63"
+ {
+ "Sequence" = "3:300"
+ "DisplayName" = "8:Confirm Installation"
+ "UseDynamicProperties" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdAdminConfirmDlg.wid"
+ "Properties"
+ {
+ "BannerBitmap"
+ {
+ "Name" = "8:BannerBitmap"
+ "DisplayName" = "8:#1001"
+ "Description" = "8:#1101"
+ "Type" = "3:8"
+ "ContextData" = "8:Bitmap"
+ "Attributes" = "3:4"
+ "Setting" = "3:1"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ }
+ }
+ "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_F285AFF8D22243D7903DBAD8EC3E139C"
+ {
+ "Sequence" = "3:100"
+ "DisplayName" = "8:Welcome"
+ "UseDynamicProperties" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdAdminWelcomeDlg.wid"
+ "Properties"
+ {
+ "BannerBitmap"
+ {
+ "Name" = "8:BannerBitmap"
+ "DisplayName" = "8:#1001"
+ "Description" = "8:#1101"
+ "Type" = "3:8"
+ "ContextData" = "8:Bitmap"
+ "Attributes" = "3:4"
+ "Setting" = "3:1"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ "CopyrightWarning"
+ {
+ "Name" = "8:CopyrightWarning"
+ "DisplayName" = "8:#1002"
+ "Description" = "8:#1102"
+ "Type" = "3:3"
+ "ContextData" = "8:"
+ "Attributes" = "3:0"
+ "Setting" = "3:1"
+ "Value" = "8:#1202"
+ "DefaultValue" = "8:#1202"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ "Welcome"
+ {
+ "Name" = "8:Welcome"
+ "DisplayName" = "8:#1003"
+ "Description" = "8:#1103"
+ "Type" = "3:3"
+ "ContextData" = "8:"
+ "Attributes" = "3:0"
+ "Setting" = "3:1"
+ "Value" = "8:#1203"
+ "DefaultValue" = "8:#1203"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ }
+ }
+ }
+ }
+ "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_2276453487CB415BBCEEFB39CD7A66AA"
+ {
+ "Name" = "8:#1901"
+ "Sequence" = "3:2"
+ "Attributes" = "3:2"
+ "Dialogs"
+ {
+ "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_9A217690AF354B4B96CA3C6C5A6D97FB"
+ {
+ "Sequence" = "3:100"
+ "DisplayName" = "8:Progress"
+ "UseDynamicProperties" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdAdminProgressDlg.wid"
+ "Properties"
+ {
+ "BannerBitmap"
+ {
+ "Name" = "8:BannerBitmap"
+ "DisplayName" = "8:#1001"
+ "Description" = "8:#1101"
+ "Type" = "3:8"
+ "ContextData" = "8:Bitmap"
+ "Attributes" = "3:4"
+ "Setting" = "3:1"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ "ShowProgress"
+ {
+ "Name" = "8:ShowProgress"
+ "DisplayName" = "8:#1009"
+ "Description" = "8:#1109"
+ "Type" = "3:5"
+ "ContextData" = "8:1;True=1;False=0"
+ "Attributes" = "3:0"
+ "Setting" = "3:0"
+ "Value" = "3:1"
+ "DefaultValue" = "3:1"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ }
+ }
+ }
+ }
+ "{2479F3F5-0309-486D-8047-8187E2CE5BA0}:_258605F946F2490BA672C041D8995724"
+ {
+ "UseDynamicProperties" = "11:FALSE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdBasicDialogs.wim"
+ }
+ "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_6C1AF69E502F4F9986E140DACB722177"
+ {
+ "Name" = "8:#1902"
+ "Sequence" = "3:1"
+ "Attributes" = "3:3"
+ "Dialogs"
+ {
+ "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_C01904FBFF1B4A69AF33AD566F06E68A"
+ {
+ "Sequence" = "3:100"
+ "DisplayName" = "8:Finished"
+ "UseDynamicProperties" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdFinishedDlg.wid"
+ "Properties"
+ {
+ "BannerBitmap"
+ {
+ "Name" = "8:BannerBitmap"
+ "DisplayName" = "8:#1001"
+ "Description" = "8:#1101"
+ "Type" = "3:8"
+ "ContextData" = "8:Bitmap"
+ "Attributes" = "3:4"
+ "Setting" = "3:1"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ "UpdateText"
+ {
+ "Name" = "8:UpdateText"
+ "DisplayName" = "8:#1058"
+ "Description" = "8:#1158"
+ "Type" = "3:15"
+ "ContextData" = "8:"
+ "Attributes" = "3:0"
+ "Setting" = "3:1"
+ "Value" = "8:#1258"
+ "DefaultValue" = "8:#1258"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ }
+ }
+ }
+ }
+ "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_CD7C137B3CE24EF89BE8D010E1666A20"
+ {
+ "Name" = "8:#1901"
+ "Sequence" = "3:1"
+ "Attributes" = "3:2"
+ "Dialogs"
+ {
+ "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_7C22099C5BBB4AFEB45AC3600B941C9E"
+ {
+ "Sequence" = "3:100"
+ "DisplayName" = "8:Progress"
+ "UseDynamicProperties" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdProgressDlg.wid"
+ "Properties"
+ {
+ "BannerBitmap"
+ {
+ "Name" = "8:BannerBitmap"
+ "DisplayName" = "8:#1001"
+ "Description" = "8:#1101"
+ "Type" = "3:8"
+ "ContextData" = "8:Bitmap"
+ "Attributes" = "3:4"
+ "Setting" = "3:1"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ "ShowProgress"
+ {
+ "Name" = "8:ShowProgress"
+ "DisplayName" = "8:#1009"
+ "Description" = "8:#1109"
+ "Type" = "3:5"
+ "ContextData" = "8:1;True=1;False=0"
+ "Attributes" = "3:0"
+ "Setting" = "3:0"
+ "Value" = "3:1"
+ "DefaultValue" = "3:1"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ }
+ }
+ }
+ }
+ "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_D786155F3664469E96B6923728AA6F4A"
+ {
+ "Name" = "8:#1902"
+ "Sequence" = "3:2"
+ "Attributes" = "3:3"
+ "Dialogs"
+ {
+ "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_5E9FB89D54184C1D8B6E948A387024AD"
+ {
+ "Sequence" = "3:100"
+ "DisplayName" = "8:Finished"
+ "UseDynamicProperties" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdAdminFinishedDlg.wid"
+ "Properties"
+ {
+ "BannerBitmap"
+ {
+ "Name" = "8:BannerBitmap"
+ "DisplayName" = "8:#1001"
+ "Description" = "8:#1101"
+ "Type" = "3:8"
+ "ContextData" = "8:Bitmap"
+ "Attributes" = "3:4"
+ "Setting" = "3:1"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ }
+ }
+ }
+ }
+ "{2479F3F5-0309-486D-8047-8187E2CE5BA0}:_E285241C0CE447ED89575C5493834D34"
+ {
+ "UseDynamicProperties" = "11:FALSE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdUserInterface.wim"
+ }
+ "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_F95987A70C394869BFF4B859A0AFEBA2"
+ {
+ "Name" = "8:#1900"
+ "Sequence" = "3:1"
+ "Attributes" = "3:1"
+ "Dialogs"
+ {
+ "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_A1DF1B3F6E744D48A1B00B3EC2FA4556"
+ {
+ "Sequence" = "3:200"
+ "DisplayName" = "8:Installation Folder"
+ "UseDynamicProperties" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdFolderDlg.wid"
+ "Properties"
+ {
+ "BannerBitmap"
+ {
+ "Name" = "8:BannerBitmap"
+ "DisplayName" = "8:#1001"
+ "Description" = "8:#1101"
+ "Type" = "3:8"
+ "ContextData" = "8:Bitmap"
+ "Attributes" = "3:4"
+ "Setting" = "3:1"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ "InstallAllUsersVisible"
+ {
+ "Name" = "8:InstallAllUsersVisible"
+ "DisplayName" = "8:#1059"
+ "Description" = "8:#1159"
+ "Type" = "3:5"
+ "ContextData" = "8:1;True=1;False=0"
+ "Attributes" = "3:0"
+ "Setting" = "3:0"
+ "Value" = "3:1"
+ "DefaultValue" = "3:1"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ }
+ }
+ "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_C8707683F88C49AC810947E8BA3F4706"
+ {
+ "Sequence" = "3:100"
+ "DisplayName" = "8:Welcome"
+ "UseDynamicProperties" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdWelcomeDlg.wid"
+ "Properties"
+ {
+ "BannerBitmap"
+ {
+ "Name" = "8:BannerBitmap"
+ "DisplayName" = "8:#1001"
+ "Description" = "8:#1101"
+ "Type" = "3:8"
+ "ContextData" = "8:Bitmap"
+ "Attributes" = "3:4"
+ "Setting" = "3:1"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ "CopyrightWarning"
+ {
+ "Name" = "8:CopyrightWarning"
+ "DisplayName" = "8:#1002"
+ "Description" = "8:#1102"
+ "Type" = "3:3"
+ "ContextData" = "8:"
+ "Attributes" = "3:0"
+ "Setting" = "3:1"
+ "Value" = "8:#1202"
+ "DefaultValue" = "8:#1202"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ "Welcome"
+ {
+ "Name" = "8:Welcome"
+ "DisplayName" = "8:#1003"
+ "Description" = "8:#1103"
+ "Type" = "3:3"
+ "ContextData" = "8:"
+ "Attributes" = "3:0"
+ "Setting" = "3:1"
+ "Value" = "8:#1203"
+ "DefaultValue" = "8:#1203"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ }
+ }
+ "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_E6AA5AC4B46D4028A0117E93AF90EF6A"
+ {
+ "Sequence" = "3:300"
+ "DisplayName" = "8:Confirm Installation"
+ "UseDynamicProperties" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdConfirmDlg.wid"
+ "Properties"
+ {
+ "BannerBitmap"
+ {
+ "Name" = "8:BannerBitmap"
+ "DisplayName" = "8:#1001"
+ "Description" = "8:#1101"
+ "Type" = "3:8"
+ "ContextData" = "8:Bitmap"
+ "Attributes" = "3:4"
+ "Setting" = "3:1"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ }
+ }
+ }
+ }
+ }
+ "MergeModule"
+ {
+ }
+ "ProjectOutput"
+ {
+ }
+ }
+}
diff --git a/installer/installer.sln b/installer/installer.sln
new file mode 100644
index 0000000..b52361c
--- /dev/null
+++ b/installer/installer.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.5.33627.172
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "installer", "installer.vdproj", "{B355CB61-F7C4-4232-8E16-CE9441346436}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Default = Debug|Default
+ Release|Default = Release|Default
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {B355CB61-F7C4-4232-8E16-CE9441346436}.Debug|Default.ActiveCfg = Debug
+ {B355CB61-F7C4-4232-8E16-CE9441346436}.Debug|Default.Build.0 = Debug
+ {B355CB61-F7C4-4232-8E16-CE9441346436}.Release|Default.ActiveCfg = Release
+ {B355CB61-F7C4-4232-8E16-CE9441346436}.Release|Default.Build.0 = Release
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {F6A321D0-7C4F-4E10-B891-3E75011F78C5}
+ EndGlobalSection
+EndGlobal
diff --git a/installer/installer.vdproj b/installer/installer.vdproj
new file mode 100644
index 0000000..80aa3b2
--- /dev/null
+++ b/installer/installer.vdproj
@@ -0,0 +1,761 @@
+"DeployProject"
+{
+"VSVersion" = "3:800"
+"ProjectType" = "8:{978C614F-708E-4E1A-B201-565925725DBA}"
+"IsWebType" = "8:FALSE"
+"ProjectName" = "8:installer"
+"LanguageId" = "3:1033"
+"CodePage" = "3:1252"
+"UILanguageId" = "3:1033"
+"SccProjectName" = "8:"
+"SccLocalPath" = "8:"
+"SccAuxPath" = "8:"
+"SccProvider" = "8:"
+ "Hierarchy"
+ {
+ "Entry"
+ {
+ "MsmKey" = "8:_8B48DC19D11942ABBE0C7A1402172A07"
+ "OwnerKey" = "8:_UNDEFINED"
+ "MsmSig" = "8:_UNDEFINED"
+ }
+ "Entry"
+ {
+ "MsmKey" = "8:_CB44E61B41964776BF2E52F12480675E"
+ "OwnerKey" = "8:_UNDEFINED"
+ "MsmSig" = "8:_UNDEFINED"
+ }
+ }
+ "Configurations"
+ {
+ "Debug"
+ {
+ "DisplayName" = "8:Debug"
+ "IsDebugOnly" = "11:TRUE"
+ "IsReleaseOnly" = "11:FALSE"
+ "OutputFilename" = "8:Debug\\installer.msi"
+ "PackageFilesAs" = "3:2"
+ "PackageFileSize" = "3:-2147483648"
+ "CabType" = "3:1"
+ "Compression" = "3:2"
+ "SignOutput" = "11:FALSE"
+ "CertificateFile" = "8:"
+ "PrivateKeyFile" = "8:"
+ "TimeStampServer" = "8:"
+ "InstallerBootstrapper" = "3:2"
+ "BootstrapperCfg:{63ACBE69-63AA-4F98-B2B6-99F9E24495F2}"
+ {
+ "Enabled" = "11:TRUE"
+ "PromptEnabled" = "11:TRUE"
+ "PrerequisitesLocation" = "2:1"
+ "Url" = "8:"
+ "ComponentsUrl" = "8:"
+ "Items"
+ {
+ "{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:.NETFramework,Version=v4.7.2"
+ {
+ "Name" = "8:Microsoft .NET Framework 4.7.2 (x86 and x64)"
+ "ProductCode" = "8:.NETFramework,Version=v4.7.2"
+ }
+ }
+ }
+ }
+ "Release"
+ {
+ "DisplayName" = "8:Release"
+ "IsDebugOnly" = "11:FALSE"
+ "IsReleaseOnly" = "11:TRUE"
+ "OutputFilename" = "8:..\\..\\builds\\cube-tube-installer-x64.msi"
+ "PackageFilesAs" = "3:2"
+ "PackageFileSize" = "3:-2147483648"
+ "CabType" = "3:1"
+ "Compression" = "3:2"
+ "SignOutput" = "11:FALSE"
+ "CertificateFile" = "8:"
+ "PrivateKeyFile" = "8:"
+ "TimeStampServer" = "8:"
+ "InstallerBootstrapper" = "3:2"
+ "BootstrapperCfg:{63ACBE69-63AA-4F98-B2B6-99F9E24495F2}"
+ {
+ "Enabled" = "11:TRUE"
+ "PromptEnabled" = "11:TRUE"
+ "PrerequisitesLocation" = "2:1"
+ "Url" = "8:"
+ "ComponentsUrl" = "8:"
+ "Items"
+ {
+ "{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:.NETFramework,Version=v4.7.2"
+ {
+ "Name" = "8:Microsoft .NET Framework 4.7.2 (x86 and x64)"
+ "ProductCode" = "8:.NETFramework,Version=v4.7.2"
+ }
+ }
+ }
+ }
+ }
+ "Deployable"
+ {
+ "CustomAction"
+ {
+ }
+ "DefaultFeature"
+ {
+ "Name" = "8:DefaultFeature"
+ "Title" = "8:"
+ "Description" = "8:"
+ }
+ "ExternalPersistence"
+ {
+ "LaunchCondition"
+ {
+ }
+ }
+ "File"
+ {
+ "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8B48DC19D11942ABBE0C7A1402172A07"
+ {
+ "SourcePath" = "8:..\\..\\builds\\cube-tube-windows-amd64.exe"
+ "TargetName" = "8:cube-tube-windows-amd64.exe"
+ "Tag" = "8:"
+ "Folder" = "8:_FE392AC6266F40A5BA12C30DB5516B78"
+ "Condition" = "8:"
+ "Transitive" = "11:FALSE"
+ "Vital" = "11:TRUE"
+ "ReadOnly" = "11:FALSE"
+ "Hidden" = "11:FALSE"
+ "System" = "11:FALSE"
+ "Permanent" = "11:FALSE"
+ "SharedLegacy" = "11:FALSE"
+ "PackageAs" = "3:1"
+ "Register" = "3:1"
+ "Exclude" = "11:FALSE"
+ "IsDependency" = "11:FALSE"
+ "IsolateTo" = "8:"
+ }
+ "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_CB44E61B41964776BF2E52F12480675E"
+ {
+ "SourcePath" = "8:..\\metadata\\icon.ico"
+ "TargetName" = "8:icon.ico"
+ "Tag" = "8:"
+ "Folder" = "8:_FE392AC6266F40A5BA12C30DB5516B78"
+ "Condition" = "8:"
+ "Transitive" = "11:FALSE"
+ "Vital" = "11:TRUE"
+ "ReadOnly" = "11:FALSE"
+ "Hidden" = "11:FALSE"
+ "System" = "11:FALSE"
+ "Permanent" = "11:FALSE"
+ "SharedLegacy" = "11:FALSE"
+ "PackageAs" = "3:1"
+ "Register" = "3:1"
+ "Exclude" = "11:FALSE"
+ "IsDependency" = "11:FALSE"
+ "IsolateTo" = "8:"
+ }
+ }
+ "FileType"
+ {
+ }
+ "Folder"
+ {
+ "{1525181F-901A-416C-8A58-119130FE478E}:_8C52B4D6CA19438E912584BB847A88C4"
+ {
+ "Name" = "8:#1916"
+ "AlwaysCreate" = "11:FALSE"
+ "Condition" = "8:"
+ "Transitive" = "11:FALSE"
+ "Property" = "8:DesktopFolder"
+ "Folders"
+ {
+ }
+ }
+ "{1525181F-901A-416C-8A58-119130FE478E}:_D5392E2DA1B749BB891650F30892B215"
+ {
+ "Name" = "8:#1919"
+ "AlwaysCreate" = "11:FALSE"
+ "Condition" = "8:"
+ "Transitive" = "11:FALSE"
+ "Property" = "8:ProgramMenuFolder"
+ "Folders"
+ {
+ }
+ }
+ "{3C67513D-01DD-4637-8A68-80971EB9504F}:_FE392AC6266F40A5BA12C30DB5516B78"
+ {
+ "DefaultLocation" = "8:[ProgramFiles64Folder][Manufacturer]\\[ProductName]"
+ "Name" = "8:#1925"
+ "AlwaysCreate" = "11:FALSE"
+ "Condition" = "8:"
+ "Transitive" = "11:FALSE"
+ "Property" = "8:TARGETDIR"
+ "Folders"
+ {
+ }
+ }
+ }
+ "LaunchCondition"
+ {
+ }
+ "Locator"
+ {
+ }
+ "MsiBootstrapper"
+ {
+ "LangId" = "3:1033"
+ "RequiresElevation" = "11:FALSE"
+ }
+ "Product"
+ {
+ "Name" = "8:Microsoft Visual Studio"
+ "ProductName" = "8:Cube Tube"
+ "ProductCode" = "8:{0DF427A0-5821-48F0-9CA5-B34F1123F839}"
+ "PackageCode" = "8:{27B06BB4-4B81-4D50-A8E0-10378563DE9D}"
+ "UpgradeCode" = "8:{CD4947B5-EF08-4530-A370-44E0B5F6F762}"
+ "AspNetVersion" = "8:4.0.30319.0"
+ "RestartWWWService" = "11:FALSE"
+ "RemovePreviousVersions" = "11:TRUE"
+ "DetectNewerInstalledVersion" = "11:TRUE"
+ "InstallAllUsers" = "11:FALSE"
+ "ProductVersion" = "8:0.1.1"
+ "Manufacturer" = "8:death.au"
+ "ARPHELPTELEPHONE" = "8:"
+ "ARPHELPLINK" = "8:"
+ "Title" = "8:Cube Tube Installer"
+ "Subject" = "8:"
+ "ARPCONTACT" = "8:death.au"
+ "Keywords" = "8:"
+ "ARPCOMMENTS" = "8:Cube Tube"
+ "ARPURLINFOABOUT" = "8:"
+ "ARPPRODUCTICON" = "8:_CB44E61B41964776BF2E52F12480675E"
+ "ARPIconIndex" = "3:0"
+ "SearchPath" = "8:"
+ "UseSystemSearchPath" = "11:TRUE"
+ "TargetPlatform" = "3:1"
+ "PreBuildEvent" = "8:"
+ "PostBuildEvent" = "8:"
+ "RunPostBuildEvent" = "3:0"
+ }
+ "Registry"
+ {
+ "HKLM"
+ {
+ "Keys"
+ {
+ "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_638ADCEBDB6040CA9692564EBAED209F"
+ {
+ "Name" = "8:Software"
+ "Condition" = "8:"
+ "AlwaysCreate" = "11:FALSE"
+ "DeleteAtUninstall" = "11:FALSE"
+ "Transitive" = "11:FALSE"
+ "Keys"
+ {
+ "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_CB383D135A0F41D49F1166D62F4E5B42"
+ {
+ "Name" = "8:[Manufacturer]"
+ "Condition" = "8:"
+ "AlwaysCreate" = "11:FALSE"
+ "DeleteAtUninstall" = "11:FALSE"
+ "Transitive" = "11:FALSE"
+ "Keys"
+ {
+ }
+ "Values"
+ {
+ }
+ }
+ }
+ "Values"
+ {
+ }
+ }
+ }
+ }
+ "HKCU"
+ {
+ "Keys"
+ {
+ "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_767D271A073F46F9BEF8F71A71AB3646"
+ {
+ "Name" = "8:Software"
+ "Condition" = "8:"
+ "AlwaysCreate" = "11:FALSE"
+ "DeleteAtUninstall" = "11:FALSE"
+ "Transitive" = "11:FALSE"
+ "Keys"
+ {
+ "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_3E2EF3C2D47640F9ACAA54251E50687D"
+ {
+ "Name" = "8:[Manufacturer]"
+ "Condition" = "8:"
+ "AlwaysCreate" = "11:FALSE"
+ "DeleteAtUninstall" = "11:FALSE"
+ "Transitive" = "11:FALSE"
+ "Keys"
+ {
+ }
+ "Values"
+ {
+ }
+ }
+ }
+ "Values"
+ {
+ }
+ }
+ }
+ }
+ "HKCR"
+ {
+ "Keys"
+ {
+ }
+ }
+ "HKU"
+ {
+ "Keys"
+ {
+ }
+ }
+ "HKPU"
+ {
+ "Keys"
+ {
+ }
+ }
+ }
+ "Sequences"
+ {
+ }
+ "Shortcut"
+ {
+ "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_96806951FD8247D18ACFDD28CF13DC84"
+ {
+ "Name" = "8:Cube Tube"
+ "Arguments" = "8:"
+ "Description" = "8:"
+ "ShowCmd" = "3:1"
+ "IconIndex" = "3:0"
+ "Transitive" = "11:FALSE"
+ "Target" = "8:_8B48DC19D11942ABBE0C7A1402172A07"
+ "Folder" = "8:_8C52B4D6CA19438E912584BB847A88C4"
+ "WorkingFolder" = "8:_FE392AC6266F40A5BA12C30DB5516B78"
+ "Icon" = "8:_CB44E61B41964776BF2E52F12480675E"
+ "Feature" = "8:"
+ }
+ "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_FA3A6FA4ADF5411AA1478FE09BD4C499"
+ {
+ "Name" = "8:Cube Tube"
+ "Arguments" = "8:"
+ "Description" = "8:"
+ "ShowCmd" = "3:1"
+ "IconIndex" = "3:0"
+ "Transitive" = "11:FALSE"
+ "Target" = "8:_8B48DC19D11942ABBE0C7A1402172A07"
+ "Folder" = "8:_D5392E2DA1B749BB891650F30892B215"
+ "WorkingFolder" = "8:_FE392AC6266F40A5BA12C30DB5516B78"
+ "Icon" = "8:_CB44E61B41964776BF2E52F12480675E"
+ "Feature" = "8:"
+ }
+ }
+ "UserInterface"
+ {
+ "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_098F2EE2CAEE410195CE081E2FAF5FE2"
+ {
+ "Name" = "8:#1900"
+ "Sequence" = "3:2"
+ "Attributes" = "3:1"
+ "Dialogs"
+ {
+ "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_5E2C5A84F47F4319A72E9410D94EE847"
+ {
+ "Sequence" = "3:200"
+ "DisplayName" = "8:Installation Folder"
+ "UseDynamicProperties" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdAdminFolderDlg.wid"
+ "Properties"
+ {
+ "BannerBitmap"
+ {
+ "Name" = "8:BannerBitmap"
+ "DisplayName" = "8:#1001"
+ "Description" = "8:#1101"
+ "Type" = "3:8"
+ "ContextData" = "8:Bitmap"
+ "Attributes" = "3:4"
+ "Setting" = "3:1"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ }
+ }
+ "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_7143F0C480E346A38A0310E2734D9A63"
+ {
+ "Sequence" = "3:300"
+ "DisplayName" = "8:Confirm Installation"
+ "UseDynamicProperties" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdAdminConfirmDlg.wid"
+ "Properties"
+ {
+ "BannerBitmap"
+ {
+ "Name" = "8:BannerBitmap"
+ "DisplayName" = "8:#1001"
+ "Description" = "8:#1101"
+ "Type" = "3:8"
+ "ContextData" = "8:Bitmap"
+ "Attributes" = "3:4"
+ "Setting" = "3:1"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ }
+ }
+ "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_F285AFF8D22243D7903DBAD8EC3E139C"
+ {
+ "Sequence" = "3:100"
+ "DisplayName" = "8:Welcome"
+ "UseDynamicProperties" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdAdminWelcomeDlg.wid"
+ "Properties"
+ {
+ "BannerBitmap"
+ {
+ "Name" = "8:BannerBitmap"
+ "DisplayName" = "8:#1001"
+ "Description" = "8:#1101"
+ "Type" = "3:8"
+ "ContextData" = "8:Bitmap"
+ "Attributes" = "3:4"
+ "Setting" = "3:1"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ "CopyrightWarning"
+ {
+ "Name" = "8:CopyrightWarning"
+ "DisplayName" = "8:#1002"
+ "Description" = "8:#1102"
+ "Type" = "3:3"
+ "ContextData" = "8:"
+ "Attributes" = "3:0"
+ "Setting" = "3:1"
+ "Value" = "8:#1202"
+ "DefaultValue" = "8:#1202"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ "Welcome"
+ {
+ "Name" = "8:Welcome"
+ "DisplayName" = "8:#1003"
+ "Description" = "8:#1103"
+ "Type" = "3:3"
+ "ContextData" = "8:"
+ "Attributes" = "3:0"
+ "Setting" = "3:1"
+ "Value" = "8:#1203"
+ "DefaultValue" = "8:#1203"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ }
+ }
+ }
+ }
+ "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_2276453487CB415BBCEEFB39CD7A66AA"
+ {
+ "Name" = "8:#1901"
+ "Sequence" = "3:2"
+ "Attributes" = "3:2"
+ "Dialogs"
+ {
+ "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_9A217690AF354B4B96CA3C6C5A6D97FB"
+ {
+ "Sequence" = "3:100"
+ "DisplayName" = "8:Progress"
+ "UseDynamicProperties" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdAdminProgressDlg.wid"
+ "Properties"
+ {
+ "BannerBitmap"
+ {
+ "Name" = "8:BannerBitmap"
+ "DisplayName" = "8:#1001"
+ "Description" = "8:#1101"
+ "Type" = "3:8"
+ "ContextData" = "8:Bitmap"
+ "Attributes" = "3:4"
+ "Setting" = "3:1"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ "ShowProgress"
+ {
+ "Name" = "8:ShowProgress"
+ "DisplayName" = "8:#1009"
+ "Description" = "8:#1109"
+ "Type" = "3:5"
+ "ContextData" = "8:1;True=1;False=0"
+ "Attributes" = "3:0"
+ "Setting" = "3:0"
+ "Value" = "3:1"
+ "DefaultValue" = "3:1"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ }
+ }
+ }
+ }
+ "{2479F3F5-0309-486D-8047-8187E2CE5BA0}:_258605F946F2490BA672C041D8995724"
+ {
+ "UseDynamicProperties" = "11:FALSE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdBasicDialogs.wim"
+ }
+ "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_6C1AF69E502F4F9986E140DACB722177"
+ {
+ "Name" = "8:#1902"
+ "Sequence" = "3:1"
+ "Attributes" = "3:3"
+ "Dialogs"
+ {
+ "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_C01904FBFF1B4A69AF33AD566F06E68A"
+ {
+ "Sequence" = "3:100"
+ "DisplayName" = "8:Finished"
+ "UseDynamicProperties" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdFinishedDlg.wid"
+ "Properties"
+ {
+ "BannerBitmap"
+ {
+ "Name" = "8:BannerBitmap"
+ "DisplayName" = "8:#1001"
+ "Description" = "8:#1101"
+ "Type" = "3:8"
+ "ContextData" = "8:Bitmap"
+ "Attributes" = "3:4"
+ "Setting" = "3:1"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ "UpdateText"
+ {
+ "Name" = "8:UpdateText"
+ "DisplayName" = "8:#1058"
+ "Description" = "8:#1158"
+ "Type" = "3:15"
+ "ContextData" = "8:"
+ "Attributes" = "3:0"
+ "Setting" = "3:1"
+ "Value" = "8:#1258"
+ "DefaultValue" = "8:#1258"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ }
+ }
+ }
+ }
+ "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_CD7C137B3CE24EF89BE8D010E1666A20"
+ {
+ "Name" = "8:#1901"
+ "Sequence" = "3:1"
+ "Attributes" = "3:2"
+ "Dialogs"
+ {
+ "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_7C22099C5BBB4AFEB45AC3600B941C9E"
+ {
+ "Sequence" = "3:100"
+ "DisplayName" = "8:Progress"
+ "UseDynamicProperties" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdProgressDlg.wid"
+ "Properties"
+ {
+ "BannerBitmap"
+ {
+ "Name" = "8:BannerBitmap"
+ "DisplayName" = "8:#1001"
+ "Description" = "8:#1101"
+ "Type" = "3:8"
+ "ContextData" = "8:Bitmap"
+ "Attributes" = "3:4"
+ "Setting" = "3:1"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ "ShowProgress"
+ {
+ "Name" = "8:ShowProgress"
+ "DisplayName" = "8:#1009"
+ "Description" = "8:#1109"
+ "Type" = "3:5"
+ "ContextData" = "8:1;True=1;False=0"
+ "Attributes" = "3:0"
+ "Setting" = "3:0"
+ "Value" = "3:1"
+ "DefaultValue" = "3:1"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ }
+ }
+ }
+ }
+ "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_D786155F3664469E96B6923728AA6F4A"
+ {
+ "Name" = "8:#1902"
+ "Sequence" = "3:2"
+ "Attributes" = "3:3"
+ "Dialogs"
+ {
+ "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_5E9FB89D54184C1D8B6E948A387024AD"
+ {
+ "Sequence" = "3:100"
+ "DisplayName" = "8:Finished"
+ "UseDynamicProperties" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdAdminFinishedDlg.wid"
+ "Properties"
+ {
+ "BannerBitmap"
+ {
+ "Name" = "8:BannerBitmap"
+ "DisplayName" = "8:#1001"
+ "Description" = "8:#1101"
+ "Type" = "3:8"
+ "ContextData" = "8:Bitmap"
+ "Attributes" = "3:4"
+ "Setting" = "3:1"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ }
+ }
+ }
+ }
+ "{2479F3F5-0309-486D-8047-8187E2CE5BA0}:_E285241C0CE447ED89575C5493834D34"
+ {
+ "UseDynamicProperties" = "11:FALSE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdUserInterface.wim"
+ }
+ "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_F95987A70C394869BFF4B859A0AFEBA2"
+ {
+ "Name" = "8:#1900"
+ "Sequence" = "3:1"
+ "Attributes" = "3:1"
+ "Dialogs"
+ {
+ "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_A1DF1B3F6E744D48A1B00B3EC2FA4556"
+ {
+ "Sequence" = "3:200"
+ "DisplayName" = "8:Installation Folder"
+ "UseDynamicProperties" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdFolderDlg.wid"
+ "Properties"
+ {
+ "BannerBitmap"
+ {
+ "Name" = "8:BannerBitmap"
+ "DisplayName" = "8:#1001"
+ "Description" = "8:#1101"
+ "Type" = "3:8"
+ "ContextData" = "8:Bitmap"
+ "Attributes" = "3:4"
+ "Setting" = "3:1"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ "InstallAllUsersVisible"
+ {
+ "Name" = "8:InstallAllUsersVisible"
+ "DisplayName" = "8:#1059"
+ "Description" = "8:#1159"
+ "Type" = "3:5"
+ "ContextData" = "8:1;True=1;False=0"
+ "Attributes" = "3:0"
+ "Setting" = "3:0"
+ "Value" = "3:1"
+ "DefaultValue" = "3:1"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ }
+ }
+ "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_C8707683F88C49AC810947E8BA3F4706"
+ {
+ "Sequence" = "3:100"
+ "DisplayName" = "8:Welcome"
+ "UseDynamicProperties" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdWelcomeDlg.wid"
+ "Properties"
+ {
+ "BannerBitmap"
+ {
+ "Name" = "8:BannerBitmap"
+ "DisplayName" = "8:#1001"
+ "Description" = "8:#1101"
+ "Type" = "3:8"
+ "ContextData" = "8:Bitmap"
+ "Attributes" = "3:4"
+ "Setting" = "3:1"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ "CopyrightWarning"
+ {
+ "Name" = "8:CopyrightWarning"
+ "DisplayName" = "8:#1002"
+ "Description" = "8:#1102"
+ "Type" = "3:3"
+ "ContextData" = "8:"
+ "Attributes" = "3:0"
+ "Setting" = "3:1"
+ "Value" = "8:#1202"
+ "DefaultValue" = "8:#1202"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ "Welcome"
+ {
+ "Name" = "8:Welcome"
+ "DisplayName" = "8:#1003"
+ "Description" = "8:#1103"
+ "Type" = "3:3"
+ "ContextData" = "8:"
+ "Attributes" = "3:0"
+ "Setting" = "3:1"
+ "Value" = "8:#1203"
+ "DefaultValue" = "8:#1203"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ }
+ }
+ "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_E6AA5AC4B46D4028A0117E93AF90EF6A"
+ {
+ "Sequence" = "3:300"
+ "DisplayName" = "8:Confirm Installation"
+ "UseDynamicProperties" = "11:TRUE"
+ "IsDependency" = "11:FALSE"
+ "SourcePath" = "8:\\VsdConfirmDlg.wid"
+ "Properties"
+ {
+ "BannerBitmap"
+ {
+ "Name" = "8:BannerBitmap"
+ "DisplayName" = "8:#1001"
+ "Description" = "8:#1101"
+ "Type" = "3:8"
+ "ContextData" = "8:Bitmap"
+ "Attributes" = "3:4"
+ "Setting" = "3:1"
+ "UsePlugInResources" = "11:TRUE"
+ }
+ }
+ }
+ }
+ }
+ }
+ "MergeModule"
+ {
+ }
+ "ProjectOutput"
+ {
+ }
+ }
+}
diff --git a/metadata/icon.ico b/metadata/icon.ico
new file mode 100644
index 0000000..dd77675
Binary files /dev/null and b/metadata/icon.ico differ
diff --git a/package.bat b/package.bat
index 50202b3..eb5b465 100644
--- a/package.bat
+++ b/package.bat
@@ -2,12 +2,40 @@
cd /d %~dp0
for %%I in (.) do set CurrDirName=%%~nxI
+for /F %%a IN ('powershell -command "$([guid]::NewGuid().ToString().toUpper())"') DO (set newProductCode=%%a)
+for /F %%a IN ('powershell -command "$([guid]::NewGuid().ToString().toUpper())"') DO (set newPackageCode=%%a)
+
+@setlocal ENABLEEXTENSIONS
+
+@set version=0
+@for /F "tokens=*" %%A in (./metadata/game_metadata.txt) do @call :CheckForVersion "%%A"
cd ..
@echo on
dragonruby-publish --only-package %CurrDirName%
@echo off
cd builds
+
+if exist ./%CurrDirName%-windows-amd64.exe (
+if exist ../%CurrDirName%/installer/installer.vdproj (
+ echo "Building windows installer..."
+ for /F "tokens=* USEBACKQ" %%t IN (`findstr /c:"%version%" ..\%CurrDirName%\installer\installer.vdproj`) do (SET OldVersion=%%t)
+ if defined OldVersion (
+ echo "version already the same"
+ ) else (
+ echo "need to update version & product/package codes (%version%, %newProductCode%, %newPackageCode%)"
+ powershell -Command "(Get-Content ../%CurrDirName%/installer/installer.vdproj) | Foreach-Object { $_ -replace '""""ProductCode"""" = """"8:\{.*\}""""$', '""""ProductCode"""" = """"8:{%newProductCode%}""""' -replace '""""PackageCode"""" = """"8:\{.*\}""""$', '""""PackageCode"""" = """"8:{%newPackageCode%}""""' -replace '""""ProductVersion"""" = """"8:.+""""$', '""""ProductVersion"""" = """"8:%version%""' } | Out-File -encoding UTF8 ../%CurrDirName%/installer/installer.vdproj"
+ )
+ call "C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\devenv.exe" ..\%CurrDirName%\installer\installer.sln /build Release
+) else (
+ ECHO "no installer project?"
+ ECHO ../%CurrDirName%/installer/installer.vdproj
+)
+) else (
+ ECHO "no exe?"
+ ECHO ./%CurrDirName%-windows-amd64.exe
+)
+
if not exist ./%CurrDirName%.keystore (
echo "no keystore, generating keys"
keytool -genkey -v -keystore %CurrDirName%.keystore -alias %CurrDirName% -keyalg RSA -keysize 2048 -validity 10000
@@ -21,6 +49,14 @@ if exist ./%CurrDirName%-android.apk (
ECHO "no apk?"
ECHO ./%CurrDirName%-android.apk
)
+
ECHO "All done!"
explorer.exe %cd%
-PAUSE
\ No newline at end of file
+PAUSE
+@exit /b 0
+
+:CheckForVersion
+@set _line=%~1
+@set _linePrefeix=%_line:~0,8%
+@if "%_linePrefeix%" equ "version=" (@set version="%_line:~8%")
+@exit /b 0
\ No newline at end of file
diff --git a/test/tests.rb b/test/tests.rb
deleted file mode 100644
index 4212163..0000000
--- a/test/tests.rb
+++ /dev/null
@@ -1,178 +0,0 @@
-# To run the tests: ./run_tests
-#
-# Available assertions:
-# assert.true!
-# assert.false!
-# assert.equal!
-# assert.exception!
-# assert.includes!
-# assert.not_includes!
-# assert.int!
-# + any that you define
-#
-# Powered by Dragon Test: https://github.com/DragonRidersUnite/dragon_test
-
-return unless debug?
-
-test :menu_text_for_setting_val do |args, assert|
- assert.equal!(Menu.text_for_setting_val(true), "ON")
- assert.equal!(Menu.text_for_setting_val(false), "OFF")
- assert.equal!(Menu.text_for_setting_val("other"), "other")
-end
-
-test :out_of_bounds do |args, assert|
- grid = {
- x: 0,
- y: 0,
- w: 1280,
- h: 720,
- }
- assert.true!(out_of_bounds?(grid, { x: -30, y: 30, w: 24, h: 24 }))
- assert.true!(out_of_bounds?(grid, { x: 30, y: -50, w: 24, h: 24 }))
- assert.false!(out_of_bounds?(grid, { x: 30, y: 30, w: 24, h: 24 }))
-end
-
-test :angle_for_dir do |args, assert|
- assert.equal!(angle_for_dir(DIR_RIGHT), 0)
- assert.equal!(angle_for_dir(DIR_LEFT), 180)
- assert.equal!(angle_for_dir(DIR_UP), 90)
- assert.equal!(angle_for_dir(DIR_DOWN), 270)
-end
-
-test :vel_from_angle do |args, assert|
- it "calculates core four angles properly" do
- assert.equal!(vel_from_angle(0, 5), [5.0, 0.0])
- assert.equal!(vel_from_angle(90, 5).map { |v| v.round(2) }, [0.0, 5.0])
- assert.equal!(vel_from_angle(180, 5).map { |v| v.round(2) }, [-5.0, 0.0])
- assert.equal!(vel_from_angle(270, 5).map { |v| v.round(2) }, [0.0, -5.0])
- end
-
- it "calculates other values as expected" do
- assert.equal!(vel_from_angle(12, 5).map { |v| v.round(2) }, [4.89, 1.04])
- end
-end
-
-test :open_entity_to_hash do |args, assert|
- it "strips OpenEntity keys" do
- args.state.foo.bar = true
- args.state.foo.biz = false
- assert.equal!(open_entity_to_hash(args.state.foo), { bar: true, biz: false })
- end
-end
-
-test :game_setting_settings_for_save do |args, assert|
- it "joins hash keys and values" do
- assert.equal!(GameSetting.settings_for_save({ fullscreen: true, sfx: false}), "fullscreen:true,sfx:false")
- end
-end
-
-test :text do |args, assert|
- it "returns the value for the passed in key" do
- assert.equal!(text(:fullscreen), "Fullscreen")
- end
-
- it "raises when the key isn't present" do
- assert.exception!(KeyError, "Key not found: :not_present") { text(:not_present) }
- end
-end
-
-test :opposite_angle do |args, assert|
- it "returns the diametrically opposed angle" do
- assert.equal!(opposite_angle(0), 180)
- assert.equal!(opposite_angle(180), 0)
- assert.equal!(opposite_angle(360), 180)
- assert.equal!(opposite_angle(90), 270)
- assert.equal!(opposite_angle(270), 90)
- end
-end
-
-test :add_to_angle do |args, assert|
- it "returns the new angle on the circle" do
- assert.equal!(add_to_angle(0, 30), 30)
- assert.equal!(add_to_angle(0, -30), 330)
- assert.equal!(add_to_angle(180, -30), 150)
- assert.equal!(add_to_angle(320, 60), 20)
- assert.equal!(add_to_angle(320, -60), 260)
- end
-end
-
-test :percent_chance? do |args, assert|
- it "returns false if the percent is 0" do
- assert.false!(percent_chance?(0))
- end
-
- it "returns true if the percent is 100" do
- assert.true!(percent_chance?(100))
- end
-
- it "returns a boolean" do
- assert.true!([TrueClass, FalseClass].include?(percent_chance?(50).class))
- end
-end
-
-test :collide do |args, assert|
- it "calls the block for every intersection of the two collections" do
- counter = 0
- enemies = [{ x: 0, y: 0, w: 8, h: 8, type: :e}, { x: 8, y: 0, w: 8, h: 8, type: :e}]
- # 2 enemies intersect with only 1 of these tiles
- tiles = [{ x: 0, y: 0, w: 32, h: 32}, { x: 32, y: 0, w: 32, h: 32}]
-
- collide(enemies, tiles) do |enemy, tile|
- counter += 1
- assert.equal!(enemy.type, :e)
- end
-
- assert.equal!(counter, 2)
- end
-
- it "has access to args in the block" do
- args.state.detect = false
- enemies = [{ x: 0, y: 0, w: 8, h: 8}]
- tiles = [{ x: 0, y: 0, w: 32, h: 32}]
-
- collide(enemies, tiles) do |enemy, tile|
- args.state.detect = true
- end
-
- assert.true!(args.state.detect)
- end
-
- it "wraps non-arrays in an array" do
- counter = 0
- tiles = [{ x: 0, y: 0, w: 32, h: 32}, { x: 32, y: 0, w: 32, h: 32}]
- # player only intersects with 1 tile
- player = { x: 0, y: 0, w: 8, h: 8, type: :player}
-
- collide(tiles, player) do |tile, player|
- counter += 1
- assert.equal!(player.type, :player)
- end
-
- assert.equal!(counter, 1)
- end
-end
-
-test :mobile do |args, assert|
- it "supports simulation setting" do
- $gtk.args.state.simulate_mobile = true
- assert.true!(mobile?)
- $gtk.args.state.simulate_mobile = false
- assert.false!(mobile?)
- end
-end
-
-test :center_of do |args, assert|
- it "returns a hash with the x and y coord of the center of the rectangle-ish object" do
- assert.equal!(center_of({ x: 100, y: 100, w: 200, h: 250 }), { x: 200.0, y: 225.0 })
- end
-
- it "errors when the object isn't rectangle-ish" do
- assert.exception!(StandardError, "entity does not have needed properties to find center; must have x, y, w, and h properties") do
- center_of({ x: 100, h: 250 })
- end
- end
-end
-
-# add your tests here
-
-run_tests