diff --git a/src/DtsObject.hx b/src/DtsObject.hx index 05814d32..3dfdb9c2 100644 --- a/src/DtsObject.hx +++ b/src/DtsObject.hx @@ -1,5 +1,6 @@ package src; +import dts.TSDrawPrimitive; import hxd.res.Sound; import h3d.col.Bounds; import src.TimeState; @@ -563,38 +564,87 @@ class DtsObject extends GameObject { indices: [] }); - for (primitive in dtsMesh.primitives) { - var k = 0; - var geometrydata = materialGeometry[primitive.matIndex]; - - for (i in primitive.firstElement...(primitive.firstElement + primitive.numElements - 2)) { - var i1 = dtsMesh.indices[i]; - var i2 = dtsMesh.indices[i + 1]; - var i3 = dtsMesh.indices[i + 2]; - - if (k % 2 == 0) { - // Swap the first and last index to mainting correct winding order + var ab = new Vector(); + var ac = new Vector(); + function addTriangleFromIndices(i1:Int, i2:Int, i3:Int, materialIndex:Int) { + ab.set(vertices[i2].x - vertices[i1].x, vertices[i2].y - vertices[i1].y, vertices[i2].z - vertices[i1].z); + ac.set(vertices[i3].x - vertices[i1].x, vertices[i3].y - vertices[i1].y, vertices[i3].z - vertices[i1].z); + var normal = ab.cross(ac); + normal.normalize(); + var dot1 = normal.dot(vertexNormals[i1]); + var dot2 = normal.dot(vertexNormals[i2]); + var dot3 = normal.dot(vertexNormals[i3]); + if (!StringTools.contains(this.dtsPath, 'helicopter.dts') && !StringTools.contains(this.dtsPath, 'tornado.dts')) + if (dot1 < 0 && dot2 < 0 && dot3 < 0) { var temp = i1; i1 = i3; i3 = temp; } + // ^ temp hardcoded fix - for (index in [i3, i2, i1]) { - var vertex = vertices[index]; - geometrydata.vertices.push(new Vector(vertex.x, vertex.y, vertex.z)); + var geometrydata = materialGeometry[materialIndex]; - var uv = dtsMesh.uv[index]; - geometrydata.uvs.push(new UV(uv.x, uv.y)); + for (index in [i3, i2, i1]) { + var vertex = vertices[index]; + geometrydata.vertices.push(new Vector(vertex.x, vertex.y, vertex.z)); - var normal = vertexNormals[index]; - geometrydata.normals.push(new Vector(normal.x, normal.y, normal.z)); + var uv = dtsMesh.uv[index]; + geometrydata.uvs.push(new UV(uv.x, uv.y)); + + var normal = vertexNormals[index]; + geometrydata.normals.push(new Vector(normal.x, normal.y, normal.z)); + } + + geometrydata.indices.push(i1); + geometrydata.indices.push(i2); + geometrydata.indices.push(i3); + } + + for (primitive in dtsMesh.primitives) { + var materialIndex = primitive.matIndex & TSDrawPrimitive.MaterialMask; + var drawType = primitive.matIndex & TSDrawPrimitive.TypeMask; + var geometrydata = materialGeometry[materialIndex]; + + if (drawType == TSDrawPrimitive.Triangles) { + var i = primitive.firstElement; + while (i < primitive.firstElement + primitive.numElements) { + var i1 = dtsMesh.indices[i]; + var i2 = dtsMesh.indices[i + 1]; + var i3 = dtsMesh.indices[i + 2]; + + addTriangleFromIndices(i1, i2, i3, materialIndex); + + i += 3; } + } else if (drawType == TSDrawPrimitive.Strip) { + var k = 0; + for (i in primitive.firstElement...(primitive.firstElement + primitive.numElements - 2)) { + var i1 = dtsMesh.indices[i]; + var i2 = dtsMesh.indices[i + 1]; + var i3 = dtsMesh.indices[i + 2]; - geometrydata.indices.push(i1); - geometrydata.indices.push(i2); - geometrydata.indices.push(i3); + if (k % 2 == 0) { + // Swap the first and last index to mainting correct winding order + var temp = i1; + i1 = i3; + i3 = temp; + } - k++; + addTriangleFromIndices(i1, i2, i3, materialIndex); + + k++; + } + } else if (drawType == TSDrawPrimitive.Fan) { + var i = primitive.firstElement; + while (i < primitive.firstElement + primitive.numElements - 2) { + var i1 = dtsMesh.indices[primitive.firstElement]; + var i2 = dtsMesh.indices[i + 1]; + var i3 = dtsMesh.indices[i + 2]; + + addTriangleFromIndices(i1, i2, i3, materialIndex); + + i++; + } } } @@ -918,18 +968,20 @@ class DtsObject extends GameObject { if (!this.useInstancing) { for (material in this.materials) { if (this.currentOpacity != 1) { - // material.blendMode = BlendMode.Alpha; - // if (this.alphaShader == null) { - // this.alphaShader = new AlphaMult(); - // } - // if (material.mainPass.getShader(AlphaMult) == null) { - // material.mainPass.addShader(this.alphaShader); - // } - // this.alphaShader.alpha = this.currentOpacity; - // } else { - // if (alphaShader != null) { - // alphaShader.alpha = this.currentOpacity; - // } + material.blendMode = BlendMode.Alpha; + if (this.alphaShader == null) { + this.alphaShader = new AlphaMult(); + } + if (material.mainPass.getShader(AlphaMult) == null) { + material.mainPass.addShader(this.alphaShader); + } + this.alphaShader.alpha = this.currentOpacity; + } else { + if (alphaShader != null) { + material.blendMode = BlendMode.None; + alphaShader.alpha = this.currentOpacity; + material.mainPass.removeShader(alphaShader); + } } } } diff --git a/src/Marble.hx b/src/Marble.hx index 24522a4d..71045761 100644 --- a/src/Marble.hx +++ b/src/Marble.hx @@ -1,5 +1,6 @@ package src; +import h3d.mat.MaterialDatabase; import shaders.MarbleReflection; import shaders.CubemapRenderer; import h3d.shader.AlphaMult; @@ -206,8 +207,6 @@ class Marble extends GameObject { this.omega = new Vector(); this.camera = new CameraController(cast this); - this.collider = new SphereCollisionEntity(cast this); - this.bounceEmitterData = new ParticleData(); this.bounceEmitterData.identifier = "MarbleBounceParticle"; this.bounceEmitterData.texture = ResourceLoader.getResource("data/particles/star.png", ResourceLoader.getTexture, this.textureResources); @@ -236,23 +235,50 @@ class Marble extends GameObject { public function init(level:MarbleWorld, onFinish:Void->Void) { this.level = level; - var geom = Sphere.defaultUnitSphere(); - geom.addUVs(); - var marbleTexture = ResourceLoader.getFileEntry("data/shapes/balls/base.marble.png").toTexture(); - var marbleMaterial = Material.create(marbleTexture); - marbleMaterial.shadows = false; - marbleMaterial.castShadows = true; + var marbleDts = new DtsObject(); + marbleDts.dtsPath = Settings.optionsSettings.marbleModel; + marbleDts.matNameOverride.set("base.marble", Settings.optionsSettings.marbleSkin + ".marble"); + marbleDts.showSequences = false; + marbleDts.useInstancing = false; + marbleDts.init(null, () -> {}); // SYNC + for (mat in marbleDts.materials) { + mat.castShadows = true; + mat.shadows = true; + mat.receiveShadows = false; + // mat.mainPass.culling = None; + + if (Settings.optionsSettings.reflectiveMarble) { + this.cubemapRenderer = new CubemapRenderer(level.scene); + mat.mainPass.addShader(new MarbleReflection(this.cubemapRenderer.cubemap)); + } + } + + // Calculate radius according to marble model (egh) + var b = marbleDts.getBounds(); + var avgRadius = (b.xSize + b.ySize + b.zSize) / 6; + this._radius = avgRadius; + + this.collider = new SphereCollisionEntity(cast this); + + this.addChild(marbleDts); + + // var geom = Sphere.defaultUnitSphere(); + // geom.addUVs(); + // var marbleTexture = ResourceLoader.getFileEntry("data/shapes/balls/base.marble.png").toTexture(); + // var marbleMaterial = Material.create(marbleTexture); + // marbleMaterial.shadows = false; + // marbleMaterial.castShadows = true; // marbleMaterial.mainPass.removeShader(marbleMaterial.textureShader); // var dtsShader = new DtsTexture(); // dtsShader.texture = marbleTexture; // dtsShader.currentOpacity = 1; // marbleMaterial.mainPass.addShader(dtsShader); - var obj = new Mesh(geom, marbleMaterial, this); - obj.scale(_radius); - if (Settings.optionsSettings.reflectiveMarble) { - this.cubemapRenderer = new CubemapRenderer(level.scene); - marbleMaterial.mainPass.addShader(new MarbleReflection(this.cubemapRenderer.cubemap)); - } + // var obj = new Mesh(geom, marbleMaterial, this); + // obj.scale(_radius * 0.1); + // if (Settings.optionsSettings.reflectiveMarble) { + // this.cubemapRenderer = new CubemapRenderer(level.scene); + // marbleMaterial.mainPass.addShader(new MarbleReflection(this.cubemapRenderer.cubemap)); + // } this.forcefield = new DtsObject(); this.forcefield.dtsPath = "data/shapes/images/glow_bounce.dts"; @@ -1486,20 +1512,13 @@ class Marble extends GameObject { teleportFadeCompletion = Util.clamp(1 - (time.currentAttemptTime - this.teleportDisableTime) / 0.5, 0, 1); if (teleportFadeCompletion > 0) { - var mesh:Mesh = cast this.children[0]; - var shad:AlphaMult = mesh.material.mainPass.getShader(AlphaMult); - if (shad == null) { - shad = new AlphaMult(); - mesh.material.mainPass.addShader(shad); - mesh.material.blendMode = Alpha; - this.teleporting = true; - } - shad.alpha = Util.lerp(1, 0.25, teleportFadeCompletion); + var ourDts:DtsObject = cast this.children[0]; + ourDts.setOpacity(Util.lerp(1, 0.25, teleportFadeCompletion)); + this.teleporting = true; } else { if (this.teleporting) { - var mesh:Mesh = cast this.children[0]; - mesh.material.mainPass.removeShader(mesh.material.mainPass.getShader(AlphaMult)); - mesh.material.blendMode = None; + var ourDts:DtsObject = cast this.children[0]; + ourDts.setOpacity(1); this.teleporting = false; } } diff --git a/src/Settings.hx b/src/Settings.hx index 6e90ab79..72539ae3 100644 --- a/src/Settings.hx +++ b/src/Settings.hx @@ -34,6 +34,9 @@ typedef OptionsSettings = { var frameRateVis:Bool; var oobInsults:Bool; var reflectiveMarble:Bool; + var marbleIndex:Int; + var marbleSkin:String; + var marbleModel:String; } typedef ControlsSettings = { @@ -88,6 +91,9 @@ class Settings { frameRateVis: true, oobInsults: true, reflectiveMarble: true, + marbleIndex: 0, + marbleSkin: "base", + marbleModel: "data/shapes/balls/ball-superball.dts", vsync: #if js true #end #if hl false @@ -175,7 +181,10 @@ class Settings { controls: controlsSettings, touch: touchSettings, stats: playStatistics, - highscoreName: highscoreName + highscoreName: highscoreName, + marbleIndex: optionsSettings.marbleIndex, + marbleSkin: optionsSettings.marbleSkin, + marbleModel: optionsSettings.marbleModel, }; var scoreCount = 0; var eggCount = 0; diff --git a/src/dts/Primitive.hx b/src/dts/Primitive.hx index 37222541..1acad529 100644 --- a/src/dts/Primitive.hx +++ b/src/dts/Primitive.hx @@ -14,7 +14,7 @@ class Primitive { var p = new Primitive(); p.firstElement = reader.readU16(); p.numElements = reader.readU16(); - p.matIndex = (reader.readU32() & 0x00ffffff); + p.matIndex = reader.readU32(); return p; } } diff --git a/src/dts/TSDrawPrimitive.hx b/src/dts/TSDrawPrimitive.hx new file mode 100644 index 00000000..45ce0d69 --- /dev/null +++ b/src/dts/TSDrawPrimitive.hx @@ -0,0 +1,12 @@ +package dts; + +@:publicFields +class TSDrawPrimitive { + static var Triangles = 0 << 30; + static var Strip = 1 << 30; + static var Fan = 2 << 30; + static var Indexed = 1 << 29; + static var NoMaterial = 1 << 28; + static var MaterialMask = ~(1 << 30 | 2 << 30 | 0 << 30 | 1 << 29 | 1 << 28); + static var TypeMask = (1 << 30 | 2 << 30 | 0 << 30); +} diff --git a/src/gui/GuiObjectShow.hx b/src/gui/GuiObjectShow.hx index fb6ebd90..f59c6713 100644 --- a/src/gui/GuiObjectShow.hx +++ b/src/gui/GuiObjectShow.hx @@ -71,6 +71,19 @@ class GuiObjectShow extends GuiControl { } } + public function changeObject(dts:DtsObject) { + if (_initialized) { + sceneObject.remove(); + sceneObject.dispose(); + sceneObject = dts; + + scene.addChild(sceneObject); + var objCenter = sceneObject.getBounds().getCenter(); + scene.camera.pos = new Vector(0, renderDistance * Math.cos(renderPitch), objCenter.z + renderDistance * Math.sin(renderPitch)); + scene.camera.target = new Vector(objCenter.x, objCenter.y, objCenter.z); + } + } + public override function renderEngine(engine:h3d.Engine) { if (_initialized) { engine.pushTarget(this.sceneTarget); diff --git a/src/gui/MarbleSelectGui.hx b/src/gui/MarbleSelectGui.hx new file mode 100644 index 00000000..822ef21a --- /dev/null +++ b/src/gui/MarbleSelectGui.hx @@ -0,0 +1,202 @@ +package gui; + +import h2d.filter.DropShadow; +import hxd.res.BitmapFont; +import h3d.prim.Polygon; +import h3d.scene.Mesh; +import h3d.shader.AlphaChannel; +import src.MarbleGame; +import h3d.Vector; +import src.ResourceLoader; +import src.DtsObject; +import src.Settings; + +class MarbleSelectGui extends GuiImage { + public function new() { + var img = ResourceLoader.getImage("data/ui/marbleSelect/marbleSelect.png"); + super(img.resource.toTile()); + this.horizSizing = Center; + this.vertSizing = Center; + this.position = new Vector(73, -59); + this.extent = new Vector(493, 361); + + var marbleData = [ + {name: "Staff's Original", dts: "data/shapes/balls/ball-superball.dts", skin: "base"}, + {name: "3D Marble", dts: "data/shapes/balls/3dMarble.dts", skin: "base"}, + {name: "Mid P", dts: "data/shapes/balls/midp.dts", skin: "base"}, + {name: "Spade", dts: "data/shapes/balls/ball-superball.dts", skin: "skin4"}, + {name: "GMD Logo", dts: "data/shapes/balls/ball-superball.dts", skin: "skin5"}, + {name: "Textured Marble", dts: "data/shapes/balls/ball-superball.dts", skin: "skin6"}, + {name: "Golden Marble", dts: "data/shapes/balls/ball-superball.dts", skin: "skin7"}, + {name: "Rainbow Marble", dts: "data/shapes/balls/ball-superball.dts", skin: "skin8"}, + {name: "Brown Swirls", dts: "data/shapes/balls/ball-superball.dts", skin: "skin9"}, + {name: "Caution Stripes", dts: "data/shapes/balls/ball-superball.dts", skin: "skin10"}, + {name: "Earth", dts: "data/shapes/balls/ball-superball.dts", skin: "skin11"}, + {name: "Golf Ball", dts: "data/shapes/balls/ball-superball.dts", skin: "skin12"}, + {name: "Jupiter", dts: "data/shapes/balls/ball-superball.dts", skin: "skin13"}, + {name: "MB Gold Marble", dts: "data/shapes/balls/ball-superball.dts", skin: "skin14"}, + {name: "MBP on the Marble!", dts: "data/shapes/balls/ball-superball.dts", skin: "skin15"}, + {name: "Moshe", dts: "data/shapes/balls/ball-superball.dts", skin: "skin16"}, + {name: "Strong Bad", dts: "data/shapes/balls/ball-superball.dts", skin: "skin17"}, + {name: "Venus", dts: "data/shapes/balls/ball-superball.dts", skin: "skin18"}, + {name: "Water", dts: "data/shapes/balls/ball-superball.dts", skin: "skin19"}, + {name: "Evil Eye", dts: "data/shapes/balls/ball-superball.dts", skin: "skin20"}, + {name: "Desert and Sky", dts: "data/shapes/balls/ball-superball.dts", skin: "skin21"}, + {name: "Dirt Marble", dts: "data/shapes/balls/ball-superball.dts", skin: "skin22"}, + {name: "Friction Textured Marble", dts: "data/shapes/balls/ball-superball.dts", skin: "skin23"}, + {name: "Grass", dts: "data/shapes/balls/ball-superball.dts", skin: "skin24"}, + {name: "Mars", dts: "data/shapes/balls/ball-superball.dts", skin: "skin25"}, + {name: "Phil's Golf Ball", dts: "data/shapes/balls/ball-superball.dts", skin: "skin26"}, + {name: "Molten", dts: "data/shapes/balls/ball-superball.dts", skin: "skin27"}, + {name: "Lightning", dts: "data/shapes/balls/ball-superball.dts", skin: "skin28"}, + {name: "Phil'sEmpire", dts: "data/shapes/balls/ball-superball.dts", skin: "skin29"}, + {name: "Matan's Red Dragon", dts: "data/shapes/balls/ball-superball.dts", skin: "skin30"}, + {name: "Metallic Marble", dts: "data/shapes/balls/ball-superball.dts", skin: "skin31"}, + {name: "Sun", dts: "data/shapes/balls/ball-superball.dts", skin: "skin32"}, + {name: "Underwater", dts: "data/shapes/balls/ball-superball.dts", skin: "skin33"}, + {name: "GarageGames logo", dts: "data/shapes/balls/garageGames.dts", skin: "base"}, + {name: "Big Marble 1", dts: "data/shapes/balls/bm1.dts", skin: "base"}, + {name: "Big Marble 2", dts: "data/shapes/balls/bm2.dts", skin: "base"}, + {name: "Big Marble 3", dts: "data/shapes/balls/bm3.dts", skin: "base"}, + {name: "Small Marble 1", dts: "data/shapes/balls/sm1.dts", skin: "base"}, + {name: "Small Marble 2", dts: "data/shapes/balls/sm2.dts", skin: "base"}, + {name: "Small Marble 3", dts: "data/shapes/balls/sm3.dts", skin: "base"}, + ]; + + var curSelection:Int = Settings.optionsSettings.marbleIndex; + + function loadButtonImages(path:String) { + var normal = ResourceLoader.getResource('${path}_n.png', ResourceLoader.getImage, this.imageResources).toTile(); + var hover = ResourceLoader.getResource('${path}_h.png', ResourceLoader.getImage, this.imageResources).toTile(); + var pressed = ResourceLoader.getResource('${path}_d.png', ResourceLoader.getImage, this.imageResources).toTile(); + var disabled = ResourceLoader.getResource('${path}_i.png', ResourceLoader.getImage, this.imageResources).toTile(); + return [normal, hover, pressed, disabled]; + } + + var markerFelt32fontdata = ResourceLoader.getFileEntry("data/font/MarkerFelt.fnt"); + var markerFelt32b = new BitmapFont(markerFelt32fontdata.entry); + @:privateAccess markerFelt32b.loader = ResourceLoader.loader; + var markerFelt32 = markerFelt32b.toSdfFont(cast 26 * Settings.uiScale, MultiChannel); + var markerFelt24 = markerFelt32b.toSdfFont(cast 18 * Settings.uiScale, MultiChannel); + var markerFelt28 = markerFelt32b.toSdfFont(cast 26 * Settings.uiScale, MultiChannel); + + var selectBtn = new GuiButton(loadButtonImages("data/ui/marbleSelect/select")); + selectBtn.horizSizing = Center; + selectBtn.vertSizing = Top; + selectBtn.position = new Vector(199, 270); + selectBtn.extent = new Vector(95, 45); + selectBtn.pressedAction = (e) -> { + Settings.optionsSettings.marbleIndex = curSelection; + Settings.optionsSettings.marbleSkin = marbleData[curSelection].skin; + Settings.optionsSettings.marbleModel = marbleData[curSelection].dts; + Settings.save(); + MarbleGame.canvas.popDialog(this); + } + this.addChild(selectBtn); + + var marbleShow = buildObjectShow(marbleData[curSelection].dts, new Vector(171, 97), new Vector(150, 150), 2.6, 0); + marbleShow.horizSizing = Center; + marbleShow.vertSizing = Bottom; + marbleShow.visible = true; + this.addChild(marbleShow); + + var titleText = new GuiMLText(markerFelt28, null); + titleText.text.textColor = 0xFFFFFF; + titleText.text.filter = new DropShadow(1.414, 0.785, 0, 1, 0x0000007F, 0.4, 1, true); + titleText.horizSizing = Center; + titleText.vertSizing = Bottom; + titleText.position = new Vector(140, 67); + titleText.extent = new Vector(213, 27); + titleText.text.text = '

Official Marbles

'; + this.addChild(titleText); + + var marbleText = new GuiMLText(markerFelt24, null); + marbleText.text.textColor = 0xFFFFFF; + marbleText.text.filter = new DropShadow(1.414, 0.785, 0, 1, 0x0000007F, 0.4, 1, true); + marbleText.horizSizing = Center; + marbleText.vertSizing = Bottom; + marbleText.position = new Vector(86, 243); + marbleText.extent = new Vector(320, 22); + marbleText.text.text = '

${marbleData[curSelection].name}

'; + this.addChild(marbleText); + + var changeMarbleText = new GuiImage(ResourceLoader.getResource("data/ui/play/change_marble_text.png", ResourceLoader.getImage, this.imageResources) + .toTile()); + changeMarbleText.horizSizing = Center; + changeMarbleText.position = new Vector(96, 26); + changeMarbleText.extent = new Vector(300, 39); + this.addChild(changeMarbleText); + + function setMarbleSelection(idx:Int) { + if (idx < 0) + idx = marbleData.length + idx; + if (idx >= marbleData.length) + idx -= marbleData.length; + curSelection = idx; + var marble = marbleData[idx]; + + marbleText.text.text = '

${marble.name}

'; + + var dtsObj = new DtsObject(); + dtsObj.dtsPath = marble.dts; + dtsObj.ambientRotate = true; + dtsObj.ambientSpinFactor /= -2; + dtsObj.showSequences = false; + dtsObj.useInstancing = false; + dtsObj.matNameOverride.set("base.marble", marble.skin + ".marble"); + dtsObj.init(null, () -> {}); // The lambda is not gonna run async anyway + for (mat in dtsObj.materials) { + mat.mainPass.enableLights = false; + mat.mainPass.culling = None; + if (mat.blendMode != Alpha && mat.blendMode != Add) + mat.mainPass.addShader(new AlphaChannel()); + } + marbleShow.changeObject(dtsObj); + } + + var nextBtn = new GuiButton(loadButtonImages("data/ui/marbleSelect/next")); + nextBtn.position = new Vector(296, 270); + nextBtn.extent = new Vector(75, 45); + nextBtn.pressedAction = (e) -> { + setMarbleSelection(curSelection + 1); + } + this.addChild(nextBtn); + + var prevBtn = new GuiButton(loadButtonImages("data/ui/marbleSelect/prev")); + prevBtn.position = new Vector(123, 270); + prevBtn.extent = new Vector(75, 45); + prevBtn.pressedAction = (e) -> { + setMarbleSelection(curSelection - 1); + } + setMarbleSelection(curSelection); + this.addChild(prevBtn); + } + + function buildObjectShow(dtsPath:String, position:Vector, extent:Vector, dist:Float = 5, pitch:Float = 0, matnameOverride:Map = null) { + var oShow = new GuiObjectShow(); + var dtsObj = new DtsObject(); + dtsObj.dtsPath = dtsPath; + dtsObj.ambientRotate = true; + dtsObj.ambientSpinFactor /= -2; + dtsObj.showSequences = false; + dtsObj.useInstancing = false; + if (matnameOverride != null) { + for (key => value in matnameOverride) { + dtsObj.matNameOverride.set(key, value); + } + } + dtsObj.init(null, () -> {}); // The lambda is not gonna run async anyway + for (mat in dtsObj.materials) { + mat.mainPass.enableLights = false; + mat.mainPass.culling = None; + if (mat.blendMode != Alpha && mat.blendMode != Add) + mat.mainPass.addShader(new AlphaChannel()); + } + oShow.sceneObject = dtsObj; + oShow.position = position; + oShow.extent = extent; + oShow.renderDistance = dist; + oShow.renderPitch = pitch; + return oShow; + } +} diff --git a/src/gui/PlayMissionGui.hx b/src/gui/PlayMissionGui.hx index 2eb83a73..13d99ca8 100644 --- a/src/gui/PlayMissionGui.hx +++ b/src/gui/PlayMissionGui.hx @@ -613,6 +613,9 @@ class PlayMissionGui extends GuiImage { var pmMarbleSelect = new GuiButton(loadButtonImages("data/ui/play/marble")); pmMarbleSelect.position = new Vector(50, 46); pmMarbleSelect.extent = new Vector(43, 43); + pmMarbleSelect.pressedAction = (e) -> { + MarbleGame.canvas.pushDialog(new MarbleSelectGui()); + } pmMorePopDlg.addChild(pmMarbleSelect); var pmStats = new GuiButton(loadButtonImages("data/ui/play/statistics"));