diff --git a/.gitignore b/.gitignore index 2725941..d61fb76 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ design/design-layout.psd +.DS_Store \ No newline at end of file diff --git a/dev/lib/impact/animation.js b/dev/lib/impact/animation.js index 37f7bc7..5557242 100755 --- a/dev/lib/impact/animation.js +++ b/dev/lib/impact/animation.js @@ -50,7 +50,7 @@ ig.Animation = ig.Class.extend({ rewind: function() { - this.timer.reset(); + this.timer.set(); this.loopCount = 0; this.tile = this.sequence[0]; return this; diff --git a/dev/lib/impact/background-map.js b/dev/lib/impact/background-map.js index 619e371..b4d7b0f 100755 --- a/dev/lib/impact/background-map.js +++ b/dev/lib/impact/background-map.js @@ -47,6 +47,10 @@ ig.BackgroundMap = ig.Map.extend({ preRenderMapToChunks: function() { var totalWidth = this.width * this.tilesize * ig.system.scale, totalHeight = this.height * this.tilesize * ig.system.scale; + + // If this layer is smaller than the chunkSize, adjust the chunkSize + // accordingly, so we don't have as much overdraw + this.chunkSize = Math.min( Math.max(totalWidth, totalHeight), this.chunkSize ); var chunkCols = Math.ceil(totalWidth / this.chunkSize), chunkRows = Math.ceil(totalHeight / this.chunkSize); @@ -133,8 +137,11 @@ ig.BackgroundMap = ig.Map.extend({ if( this.repeat ) { - dx %= this.width * this.tilesize * ig.system.scale; - dy %= this.height * this.tilesize * ig.system.scale; + var w = this.width * this.tilesize * ig.system.scale; + dx = (dx%w + w) % w; + + var h = this.height * this.tilesize * ig.system.scale; + dy = (dy%h + h) % h; } var minChunkX = Math.max( Math.floor(dx / this.chunkSize), 0 ), @@ -168,18 +175,18 @@ ig.BackgroundMap = ig.Map.extend({ ig.system.context.strokeRect( x, y, this.chunkSize, this.chunkSize ); } - // If we repeat in X and this chunks width wasn't the full chunk size + // If we repeat in X and this chunk's width wasn't the full chunk size // and the screen is not already filled, we need to draw anohter chunk // AND nudge it to be flush with the last chunk - if( this.repeat && chunk.width < this.chunkSize && x + chunk.width < ig.system.realWidth ) { - nudgeX = this.chunkSize - chunk.width; + if( this.repeat && chunk.width < this.chunkSize && x + chunk.width < ig.system.realWidth ) { + nudgeX += this.chunkSize - chunk.width; maxChunkX++; } } // Same as above, but for Y - if( this.repeat && chunk.height < this.chunkSize && y + chunk.height < ig.system.realHeight ) { - nudgeY = this.chunkSize - chunk.height; + if( this.repeat && chunk.height < this.chunkSize && y + chunk.height < ig.system.realHeight ) { + nudgeY += this.chunkSize - chunk.height; maxChunkY++; } } @@ -209,9 +216,7 @@ ig.BackgroundMap = ig.Map.extend({ // Repeat Y? if( tileY >= this.height || tileY < 0 ) { if( !this.repeat ) { continue; } - tileY = tileY > 0 - ? tileY % this.height - : ((tileY+1) % this.height) + this.height - 1; + tileY = (tileY%this.height + this.height) % this.height; } for( var mapX = -1, pxX = pxMinX; pxX < pxMaxX; mapX++, pxX += this.tilesize ) { @@ -220,9 +225,7 @@ ig.BackgroundMap = ig.Map.extend({ // Repeat X? if( tileX >= this.width || tileX < 0 ) { if( !this.repeat ) { continue; } - tileX = tileX > 0 - ? tileX % this.width - : ((tileX+1) % this.width) + this.width - 1; + tileX = (tileX%this.width + this.width) % this.width; } // Draw! diff --git a/dev/lib/impact/debug/menu.js b/dev/lib/impact/debug/menu.js index cf827f6..4bb44d6 100755 --- a/dev/lib/impact/debug/menu.js +++ b/dev/lib/impact/debug/menu.js @@ -39,7 +39,7 @@ ig.Debug = ig.Class.extend({ var style = ig.$new('link'); style.rel = 'stylesheet'; style.type = 'text/css'; - style.href = 'lib/impact/debug/debug.css'; + style.href = ig.prefix + 'lib/impact/debug/debug.css'; ig.$('body')[0].appendChild( style ); // Create the Debug Container diff --git a/dev/lib/impact/entity.js b/dev/lib/impact/entity.js index c733085..3fa961c 100755 --- a/dev/lib/impact/entity.js +++ b/dev/lib/impact/entity.js @@ -64,7 +64,7 @@ ig.Entity = ig.Class.extend({ this.last.x = this.pos.x; this.last.y = this.pos.y; this.vel.y += ig.game.gravity * ig.system.tick * this.gravityFactor; - + this.vel.x = this.getNewVelocity( this.vel.x, this.accel.x, this.friction.x, this.maxVel.x ); this.vel.y = this.getNewVelocity( this.vel.y, this.accel.y, this.friction.y, this.maxVel.y ); diff --git a/dev/lib/impact/font.js b/dev/lib/impact/font.js index eee24ed..f30d290 100755 --- a/dev/lib/impact/font.js +++ b/dev/lib/impact/font.js @@ -121,21 +121,16 @@ ig.Font = ig.Image.extend({ this.widthMap = []; this.indices = []; - var canvas = ig.$new('canvas'); - canvas.width = image.width; - canvas.height = image.height; - var ctx = canvas.getContext('2d'); - ctx.drawImage( image, 0, 0 ); - var px = ctx.getImageData(0, image.height-1, image.width, 1); + var px = ig.getImagePixels( image, 0, image.height-1, image.width, 1 ); var currentChar = 0; var currentWidth = 0; for( var x = 0; x < image.width; x++ ) { var index = x * 4 + 3; // alpha component of this pixel - if( px.data[index] != 0 ) { + if( px.data[index] > 127 ) { currentWidth++; } - else if( px.data[index] == 0 && currentWidth ) { + else if( px.data[index] < 128 && currentWidth ) { this.widthMap.push( currentWidth ); this.indices.push( x-currentWidth ); currentChar++; diff --git a/dev/lib/impact/image.js b/dev/lib/impact/image.js index 64023a3..47d124a 100755 --- a/dev/lib/impact/image.js +++ b/dev/lib/impact/image.js @@ -86,16 +86,11 @@ ig.Image = ig.Class.extend({ // and copied into another offscreen canvas with the new size. // The scaled offscreen canvas becomes the image (data) of this object. + var origPixels = ig.getImagePixels( this.data, 0, 0, this.width, this.height ); + var widthScaled = this.width * scale; var heightScaled = this.height * scale; - - var orig = ig.$new('canvas'); - orig.width = this.width; - orig.height = this.height; - var origCtx = orig.getContext('2d'); - origCtx.drawImage( this.data, 0, 0, this.width, this.height, 0, 0, this.width, this.height ); - var origPixels = origCtx.getImageData(0, 0, this.width, this.height); - + var scaled = ig.$new('canvas'); scaled.width = widthScaled; scaled.height = heightScaled; diff --git a/dev/lib/impact/impact.js b/dev/lib/impact/impact.js index 3cc9854..4109a6c 100755 --- a/dev/lib/impact/impact.js +++ b/dev/lib/impact/impact.js @@ -1,6 +1,6 @@ // ----------------------------------------------------------------------------- -// Impact Game Engine 1.20 +// Impact Game Engine 1.22 // http://impactjs.com/ // ----------------------------------------------------------------------------- @@ -56,14 +56,26 @@ Array.prototype.random = function() { return this[ Math.floor(Math.random() * this.length) ]; }; -Function.prototype.bind = Function.prototype.bind || function(bind) { - var self = this; - return function(){ - var args = Array.prototype.slice.call(arguments); - return self.apply(bind || null, args); - }; -}; +Function.prototype.bind = Function.prototype.bind || function (oThis) { + if( typeof this !== "function" ) { + throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); + } + var aArgs = Array.prototype.slice.call(arguments, 1), + fToBind = this, + fNOP = function () {}, + fBound = function () { + return fToBind.apply( + (this instanceof fNOP && oThis ? this : oThis), + aArgs.concat(Array.prototype.slice.call(arguments)) + ); + }; + + fNOP.prototype = this.prototype; + fBound.prototype = new fNOP(); + + return fBound; +}; // ----------------------------------------------------------------------------- @@ -72,7 +84,7 @@ Function.prototype.bind = Function.prototype.bind || function(bind) { window.ig = { game: null, debug: null, - version: '1.20', + version: '1.22', global: window, modules: {}, resources: [], @@ -163,7 +175,56 @@ window.ig = { return values; }, - + + // Ah, yes. I love vendor prefixes. So much fun! + setVendorAttribute: function( el, attr, val ) { + var uc = attr.charAt(0).toUpperCase() + attr.substr(1); + el[attr] = el['ms'+uc] = el['moz'+uc] = el['webkit'+uc] = el['o'+uc] = val; + }, + + + getVendorAttribute: function( el, attr ) { + var uc = attr.charAt(0).toUpperCase() + attr.substr(1); + return el[attr] || el['ms'+uc] || el['moz'+uc] || el['webkit'+uc] || el['o'+uc]; + }, + + + normalizeVendorAttribute: function( el, attr ) { + var prefixedVal = ig.getVendorAttribute( el, attr ); + if( !el[attr] && prefixedVal ) { + el[attr] = prefixedVal; + } + }, + + + // This function normalizes getImageData to extract the real, actual + // pixels from an image. The naive method recently failed on retina + // devices with a backgingStoreRatio != 1 + getImagePixels: function( image, x, y, width, height ) { + var canvas = ig.$new('canvas'); + canvas.width = image.width; + canvas.height = image.height; + var ctx = canvas.getContext('2d'); + + // Try to draw pixels as accurately as possible + ig.System.SCALE.CRISP(canvas, ctx); + + var ratio = ig.getVendorAttribute( ctx, 'backingStorePixelRatio' ) || 1; + ig.normalizeVendorAttribute( ctx, 'getImageDataHD' ); + + var realWidth = image.width / ratio, + realHeight = image.height / ratio; + + canvas.width = Math.ceil( realWidth ); + canvas.height = Math.ceil( realHeight ); + + ctx.drawImage( image, 0, 0, realWidth, realHeight ); + + return (ratio === 1) + ? ctx.getImageData( x, y, width, height ) + : ctx.getImageDataHD( x, y, width, height ); + }, + module: function( name ) { if( ig._current ) { @@ -324,8 +385,10 @@ window.ig = { ig.ua.iPhone4 = (ig.ua.iPhone && ig.ua.pixelRatio == 2); ig.ua.iPad = /iPad/i.test(navigator.userAgent); ig.ua.android = /android/i.test(navigator.userAgent); + ig.ua.winPhone = /Windows Phone/i.test(navigator.userAgent); ig.ua.iOS = ig.ua.iPhone || ig.ua.iPad; - ig.ua.mobile = ig.ua.iOS || ig.ua.android; + ig.ua.mobile = ig.ua.iOS || ig.ua.android || ig.ua.winPhone; + ig.ua.touchDevice = (('ontouchstart' in window) || (window.navigator.msMaxTouchPoints)); }, @@ -355,13 +418,8 @@ window.ig = { // Provide ig.setAnimation and ig.clearAnimation as a compatible way to use // requestAnimationFrame if available or setInterval otherwise -// Find vendor prefix, if any -var vendors = ['ms', 'moz', 'webkit', 'o']; -for( var i = 0; i < vendors.length && !window.requestAnimationFrame; i++ ) { - window.requestAnimationFrame = window[vendors[i]+'RequestAnimationFrame']; -} - // Use requestAnimationFrame if available +ig.normalizeVendorAttribute( window, 'requestAnimationFrame' ); if( window.requestAnimationFrame ) { var next = 1, anims = {}; @@ -481,13 +539,19 @@ window.ig.Class.extend = function(prop) { } Class.prototype = prototype; - Class.constructor = Class; + Class.prototype.constructor = Class; Class.extend = window.ig.Class.extend; Class.inject = inject; return Class; }; +// Merge the ImpactMixin - if present - into the 'ig' namespace. This gives other +// code the chance to modify 'ig' before it's doing any work. +if( window.ImpactMixin ) { + ig.merge(ig, window.ImpactMixin); +} + })(window); diff --git a/dev/lib/impact/input.js b/dev/lib/impact/input.js index e7819c8..4025313 100755 --- a/dev/lib/impact/input.js +++ b/dev/lib/impact/input.js @@ -125,9 +125,18 @@ ig.Input = ig.Class.extend({ ig.system.canvas.addEventListener('mouseup', this.keyup.bind(this), false ); ig.system.canvas.addEventListener('mousemove', this.mousemove.bind(this), false ); - ig.system.canvas.addEventListener('touchstart', this.keydown.bind(this), false ); - ig.system.canvas.addEventListener('touchend', this.keyup.bind(this), false ); - ig.system.canvas.addEventListener('touchmove', this.mousemove.bind(this), false ); + if( ig.ua.touchDevice ) { + // Standard + ig.system.canvas.addEventListener('touchstart', this.keydown.bind(this), false ); + ig.system.canvas.addEventListener('touchend', this.keyup.bind(this), false ); + ig.system.canvas.addEventListener('touchmove', this.mousemove.bind(this), false ); + + // MS + ig.system.canvas.addEventListener('MSPointerDown', this.keydown.bind(this), false ); + ig.system.canvas.addEventListener('MSPointerUp', this.keyup.bind(this), false ); + ig.system.canvas.addEventListener('MSPointerMove', this.mousemove.bind(this), false ); + ig.system.canvas.style.msTouchAction = 'none'; + } }, @@ -157,25 +166,20 @@ ig.Input = ig.Class.extend({ event.preventDefault(); } }, - - mousemove: function( event ) { - var el = ig.system.canvas; + + mousemove: function( event ) { + var internalWidth = parseInt(ig.system.canvas.offsetWidth) || ig.system.realWidth; + var scale = ig.system.scale * (internalWidth / ig.system.realWidth); + var pos = {left: 0, top: 0}; - while( el != null ) { - pos.left += el.offsetLeft; - pos.top += el.offsetTop; - el = el.offsetParent; - } - var tx = event.pageX; - var ty = event.pageY; - if( event.touches ) { - tx = event.touches[0].clientX; - ty = event.touches[0].clientY; + if( ig.system.canvas.getBoundingClientRect ) { + pos = ig.system.canvas.getBoundingClientRect(); } - this.mouse.x = (tx - pos.left) / ig.system.scale; - this.mouse.y = (ty - pos.top) / ig.system.scale; + var ev = event.touches ? event.touches[0] : event; + this.mouse.x = (ev.clientX - pos.left) / scale; + this.mouse.y = (ev.clientY - pos.top) / scale; }, @@ -188,7 +192,8 @@ ig.Input = ig.Class.extend({ keydown: function( event ) { - if( event.target.type == 'text' ) { return; } + var tag = event.target.tagName; + if( tag == 'INPUT' || tag == 'TEXTAREA' ) { return; } var code = event.type == 'keydown' ? event.keyCode @@ -212,7 +217,8 @@ ig.Input = ig.Class.extend({ keyup: function( event ) { - if( event.target.type == 'text' ) { return; } + var tag = event.target.tagName; + if( tag == 'INPUT' || tag == 'TEXTAREA' ) { return; } var code = event.type == 'keyup' ? event.keyCode @@ -243,13 +249,10 @@ ig.Input = ig.Class.extend({ var element = ig.$( selector ); var that = this; - element.addEventListener('touchstart', function(ev) { - that.touchStart( ev, action ); - }, false); - - element.addEventListener('touchend', function(ev) { - that.touchEnd( ev, action ); - }, false); + element.addEventListener('touchstart', function(ev) {that.touchStart( ev, action );}, false); + element.addEventListener('touchend', function(ev) {that.touchEnd( ev, action );}, false); + element.addEventListener('MSPointerDown', function(ev) {that.touchStart( ev, action );}, false); + element.addEventListener('MSPointerUp', function(ev) {that.touchEnd( ev, action );}, false); }, diff --git a/dev/lib/impact/sound.js b/dev/lib/impact/sound.js index db46866..89fad8c 100755 --- a/dev/lib/impact/sound.js +++ b/dev/lib/impact/sound.js @@ -9,6 +9,12 @@ ig.SoundManager = ig.Class.extend({ format: null, init: function() { + // Quick sanity check if the Browser supports the Audio tag + if( !ig.Sound.enabled || !window.Audio ) { + ig.Sound.enabled = false; + return; + } + // Probe sound formats and determine the file extension to load var probe = new Audio(); for( var i = 0; i < ig.Sound.use.length; i++ ) { diff --git a/dev/lib/impact/system.js b/dev/lib/impact/system.js index d654de2..a5739ef 100755 --- a/dev/lib/impact/system.js +++ b/dev/lib/impact/system.js @@ -34,6 +34,13 @@ ig.System = ig.Class.extend({ this.context = this.canvas.getContext('2d'); this.getDrawPos = ig.System.drawMode; + + // Automatically switch to crisp scaling when using a scale + // other than 1 + if( this.scale != 1 ) { + ig.System.scaleMode = ig.System.SCALE.CRISP; + } + ig.System.scaleMode( this.canvas, this.context ); }, @@ -108,7 +115,7 @@ ig.System = ig.Class.extend({ }, - getDrawPos: null, // Set through constructor + getDrawPos: null // Set through constructor }); ig.System.DRAW = { @@ -118,4 +125,21 @@ ig.System.DRAW = { }; ig.System.drawMode = ig.System.DRAW.SMOOTH; -}); \ No newline at end of file +ig.System.SCALE = { + CRISP: function( canvas, context ) { + ig.setVendorAttribute( context, 'imageSmoothingEnabled', false ); + canvas.style.imageRendering = '-moz-crisp-edges'; + canvas.style.imageRendering = '-o-crisp-edges'; + canvas.style.imageRendering = '-webkit-optimize-contrast'; + canvas.style.imageRendering = 'crisp-edges'; + canvas.style.msInterpolationMode = 'nearest-neighbor'; // No effect on Canvas :/ + }, + SMOOTH: function( canvas, context ) { + ig.setVendorAttribute( context, 'imageSmoothingEnabled', true ); + canvas.style.imageRendering = ''; + canvas.style.msInterpolationMode = ''; + } +}; +ig.System.scaleMode = ig.System.SCALE.SMOOTH; + +}); diff --git a/dev/lib/impact/timer.js b/dev/lib/impact/timer.js index 7ff455c..d87747f 100755 --- a/dev/lib/impact/timer.js +++ b/dev/lib/impact/timer.js @@ -58,7 +58,7 @@ ig.Timer = ig.Class.extend({ }); ig.Timer._last = 0; -ig.Timer.time = 0; +ig.Timer.time = Number.MIN_VALUE; ig.Timer.timeScale = 1; ig.Timer.maxStep = 0.05; diff --git a/dev/lib/weltmeister/collisiontiles-64.png b/dev/lib/weltmeister/collisiontiles-64.png index 55efd3c..0409c7c 100755 Binary files a/dev/lib/weltmeister/collisiontiles-64.png and b/dev/lib/weltmeister/collisiontiles-64.png differ diff --git a/dev/lib/weltmeister/config.js b/dev/lib/weltmeister/config.js index 417b72d..95beaef 100755 --- a/dev/lib/weltmeister/config.js +++ b/dev/lib/weltmeister/config.js @@ -44,8 +44,8 @@ wm.config = { 'view': { 'zoom': 1, - 'zoomMax': 1, - 'zoomMin': 1, + 'zoomMax': 4, + 'zoomMin': 0.125, 'grid': false }, diff --git a/dev/lib/weltmeister/edit-entities.js b/dev/lib/weltmeister/edit-entities.js index 32fd24e..80322f9 100755 --- a/dev/lib/weltmeister/edit-entities.js +++ b/dev/lib/weltmeister/edit-entities.js @@ -147,17 +147,33 @@ wm.EditEntities = ig.Class.extend({ selectEntityAt: function( x, y ) { this.selector.pos = { x: x, y: y }; + // Find all possible selections + var possibleSelections = []; for( var i = 0; i < this.entities.length; i++ ) { - var ent = this.entities[i]; - if( ent.touches(this.selector) ) { - this.selector.offset = {x: (x - ent.pos.x + ent.offset.x), y: (y - ent.pos.y + ent.offset.y)}; - this.selectEntity( ent ); - this.wasSelectedOnScaleBorder = this.isOnScaleBorder( ent, this.selector ); - return ent; + if( this.entities[i].touches(this.selector) ) { + possibleSelections.push( this.entities[i] ); } } - this.selectEntity( null ); - return false; + + // Nothing found? Early out. + if( !possibleSelections.length ) { + this.selectEntity( null ); + return false; + } + + // Find the 'next' selection + var selectedIndex = possibleSelections.indexOf(this.selectedEntity); + var nextSelection = (selectedIndex + 1) % possibleSelections.length; + var ent = possibleSelections[nextSelection]; + + // Select it! + this.selector.offset = { + x: (x - ent.pos.x + ent.offset.x), + y: (y - ent.pos.y + ent.offset.y) + }; + this.selectEntity( ent ); + this.wasSelectedOnScaleBorder = this.isOnScaleBorder( ent, this.selector ); + return ent; }, diff --git a/dev/lib/weltmeister/entities.js b/dev/lib/weltmeister/entities.js index 97e99b0..68fa638 100755 --- a/dev/lib/weltmeister/entities.js +++ b/dev/lib/weltmeister/entities.js @@ -35,7 +35,9 @@ var req = $.ajax({ var moduleNames = []; var modules = {}; for( var i = 0; i < files.length; i++ ) { - var name = files[i].replace(/^lib\/|\.js$/g,'').replace(/\//g, '.'); + var name = files[i] + .replace(new RegExp("^"+ig.lib+"|\\.js$", "g"), '') + .replace(/\//g, '.'); moduleNames.push( name ); modules[name] = files[i]; } diff --git a/dev/lib/weltmeister/evented-input.js b/dev/lib/weltmeister/evented-input.js index e453b86..b3c9dc2 100755 --- a/dev/lib/weltmeister/evented-input.js +++ b/dev/lib/weltmeister/evented-input.js @@ -15,7 +15,8 @@ wm.EventedInput = ig.Input.extend({ keydown: function( event ) { - if( event.target.type == 'text' ) { return; } + var tag = event.target.tagName; + if( tag == 'INPUT' || tag == 'TEXTAREA' ) { return; } var code = event.type == 'keydown' ? event.keyCode @@ -35,7 +36,9 @@ wm.EventedInput = ig.Input.extend({ keyup: function( event ) { - if( event.target.type == 'text' ) { return; } + var tag = event.target.tagName; + if( tag == 'INPUT' || tag == 'TEXTAREA' ) { return; } + var code = event.type == 'keyup' ? event.keyCode : (event.button == 2 ? ig.KEY.MOUSE2 : ig.KEY.MOUSE1); diff --git a/dev/lib/weltmeister/weltmeister.js b/dev/lib/weltmeister/weltmeister.js index 2ef2f26..cddc002 100755 --- a/dev/lib/weltmeister/weltmeister.js +++ b/dev/lib/weltmeister/weltmeister.js @@ -114,6 +114,11 @@ wm.Weltmeister = ig.Class.extend({ $('input#toggleSidebar').toggleClass('active'); }); + // Always unfocus current input field when clicking the canvas + $('#canvas').mousedown(function(){ + $('input:focus').blur(); + }); + this.undo = new wm.Undo( wm.config.undoLevels ); diff --git a/dev/media/04b03.font.png b/dev/media/04b03.font.png index 3e137af..846aa2c 100755 Binary files a/dev/media/04b03.font.png and b/dev/media/04b03.font.png differ diff --git a/dev/tools/bake.bat b/dev/tools/bake.bat index 9014090..014c0e6 100755 --- a/dev/tools/bake.bat +++ b/dev/tools/bake.bat @@ -8,14 +8,16 @@ SET GAME=lib/game/main.js SET OUTPUT_FILE=game.min.js -:: Change CWD to Impact's base dir and bake! +:: Change CWD to Impact's base dir cd ../ -php tools/bake.php %IMPACT_LIBRARY% %GAME% %OUTPUT_FILE% +:: Bake! +php tools/bake.php %IMPACT_LIBRARY% %GAME% %OUTPUT_FILE% + :: If you dont have the php.exe in your PATH uncomment the :: following line and point it to your php.exe -::c:/php/php.exe bake.php %IMPACT_LIBRARY% %GAME% %OUTPUT_FILE% +::c:/php/php.exe tools/bake.php %IMPACT_LIBRARY% %GAME% %OUTPUT_FILE% pause \ No newline at end of file