diff --git a/src/DtsObject.hx b/src/DtsObject.hx index 8ec9b03b..2f0320d1 100644 --- a/src/DtsObject.hx +++ b/src/DtsObject.hx @@ -403,6 +403,10 @@ class DtsObject extends GameObject { dtsshader.currentOpacity = 1; if (this.identifier == "Tornado") dtsshader.normalizeNormals = false; // These arent normalized + if (this.identifier != null && StringTools.startsWith(this.identifier, "GemBeam")) { + dtsshader.usePremultipliedAlpha = true; + dtsshader.opacityMult = 0.5; // Hardcoded + } material.mainPass.removeShader(material.textureShader); material.mainPass.addShader(dtsshader); } @@ -438,10 +442,20 @@ class DtsObject extends GameObject { material.shadows = false; } if (flags & 4 > 0) { - material.blendMode = BlendMode.Alpha; - material.mainPass.culling = h3d.mat.Data.Face.None; - material.receiveShadows = false; - material.mainPass.depthWrite = false; + if (this.identifier == null || !StringTools.startsWith(this.identifier, "GemBeam")) { + material.blendMode = BlendMode.Alpha; + + material.mainPass.culling = h3d.mat.Data.Face.None; + material.receiveShadows = false; + material.mainPass.depthWrite = false; + } + if (this.identifier != null && StringTools.startsWith(this.identifier, "GemBeam")) { + material.blendMode = BlendMode.Alpha; + material.mainPass.culling = h3d.mat.Data.Face.None; + material.receiveShadows = false; + material.mainPass.blend(SrcAlpha, OneMinusSrcAlpha); + material.mainPass.depthWrite = false; + } } if (flags & 8 > 0) { material.blendMode = BlendMode.Add; diff --git a/src/InstanceManager.hx b/src/InstanceManager.hx index 7f1ac41c..2c0562f1 100644 --- a/src/InstanceManager.hx +++ b/src/InstanceManager.hx @@ -173,7 +173,7 @@ class InstanceManager { if (dtsShader != null) { dtsShader.currentOpacity = instance.gameObject.currentOpacity; } - minfo.transparencymeshbatch.material.blendMode = Alpha; + // minfo.transparencymeshbatch.material.blendMode = Alpha; // minfo.transparencymeshbatch.material.color.a = instance.gameObject.currentOpacity; // minfo.transparencymeshbatch.material.mainPass.setPassName(minfo.mesh.material.mainPass.name); // minfo.transparencymeshbatch.shadersChanged = true; @@ -229,6 +229,12 @@ class InstanceManager { minfo.meshbatch.material.mainPass.addShader(dtsshader); minfo.meshbatch.material.mainPass.culling = mat.mainPass.culling; minfo.meshbatch.material.mainPass.depthWrite = mat.mainPass.depthWrite; + minfo.meshbatch.material.mainPass.blendSrc = mat.mainPass.blendSrc; + minfo.meshbatch.material.mainPass.blendDst = mat.mainPass.blendDst; + minfo.meshbatch.material.mainPass.blendOp = mat.mainPass.blendOp; + minfo.meshbatch.material.mainPass.blendAlphaSrc = mat.mainPass.blendAlphaSrc; + minfo.meshbatch.material.mainPass.blendAlphaDst = mat.mainPass.blendAlphaDst; + minfo.meshbatch.material.mainPass.blendAlphaOp = mat.mainPass.blendAlphaOp; minfo.dtsShader = dtsshader; } var phongshader = mat.mainPass.getShader(PhongMaterial); @@ -256,6 +262,21 @@ class InstanceManager { minfo.transparencymeshbatch = new MeshBatch(cast(cast(obj, Mesh).primitive), cast(cast(obj, Mesh)).material.clone(), scene); minfo.transparencymeshbatch.material.mainPass.removeShader(minfo.meshbatch.material.textureShader); minfo.transparencymeshbatch.material.mainPass.addShader(dtsshader); + + minfo.transparencymeshbatch.material.blendMode = Alpha; + + minfo.transparencymeshbatch.material.mainPass.culling = mat.mainPass.culling; + minfo.transparencymeshbatch.material.mainPass.depthWrite = mat.mainPass.depthWrite; + if (mat.blendMode == Alpha) { + minfo.transparencymeshbatch.material.mainPass.blendSrc = mat.mainPass.blendSrc; + minfo.transparencymeshbatch.material.mainPass.blendDst = mat.mainPass.blendDst; + minfo.transparencymeshbatch.material.mainPass.blendOp = mat.mainPass.blendOp; + minfo.transparencymeshbatch.material.mainPass.blendAlphaSrc = mat.mainPass.blendAlphaSrc; + minfo.transparencymeshbatch.material.mainPass.blendAlphaDst = mat.mainPass.blendAlphaDst; + minfo.transparencymeshbatch.material.mainPass.blendAlphaOp = mat.mainPass.blendAlphaOp; + minfo.transparencymeshbatch.material.mainPass.enableLights = mat.mainPass.enableLights; + minfo.transparencymeshbatch.material.receiveShadows = mat.receiveShadows; + } // minfo.transparencymeshbatch.material.mainPass.culling = mat.mainPass.culling; // minfo.meshbatch.material.mainPass.removeShader(minfo.meshbatch.material.mainPass.getShader(PropsValues)); diff --git a/src/MarbleWorld.hx b/src/MarbleWorld.hx index 571450ea..f76f2fa4 100644 --- a/src/MarbleWorld.hx +++ b/src/MarbleWorld.hx @@ -212,7 +212,7 @@ class MarbleWorld extends Scheduler { this.scene2d = scene2d; this.mission = mission; this.game = mission.game.toLowerCase(); - this.gameMode = GameModeFactory.getGameMode(cast this, null); + this.gameMode = GameModeFactory.getGameMode(cast this, mission.gameMode); this.replay = new Replay(mission.path, mission.isClaMission ? mission.id : 0); this.isRecording = record; this.rewindManager = new RewindManager(cast this); @@ -293,7 +293,8 @@ class MarbleWorld extends Scheduler { var musicFileName = 'data/sound/music/' + this.mission.missionInfo.music; AudioManager.playMusic(ResourceLoader.getResource(musicFileName, ResourceLoader.getAudio, this.soundResources), this.mission.missionInfo.music); MarbleGame.canvas.clearContent(); - this.endPad.generateCollider(); + if (this.endPad != null) + this.endPad.generateCollider(); this.playGui.formatGemCounter(this.gemCount, this.totalGems); Console.log("MISSION LOADED"); start(); @@ -612,6 +613,8 @@ class MarbleWorld extends Scheduler { // } else { @:privateAccess marble.helicopterEnableTime = -1e8; @:privateAccess marble.megaMarbleEnableTime = -1e8; + @:privateAccess marble.shockAbsorberEnableTime = -1e8; + @:privateAccess marble.superBounceEnableTime = -1e8; // } if (this.isRecording) { this.replay.recordCameraState(marble.camera.CameraYaw, marble.camera.CameraPitch); @@ -632,7 +635,7 @@ class MarbleWorld extends Scheduler { marble.outOfBounds = false; this.gameMode.onRespawn(marble); if (marble == this.marble && @:privateAccess !marble.isNetUpdate) - AudioManager.playSound(ResourceLoader.getResource('data/sound/spawn_alternate.wav', ResourceLoader.getAudio, this.soundResources)); + AudioManager.playSound(ResourceLoader.getResource('data/sound/spawn.wav', ResourceLoader.getAudio, this.soundResources)); } public function updateGameState() { @@ -1451,7 +1454,7 @@ class MarbleWorld extends Scheduler { } } - if (this.finishTime == null) { + if (this.finishTime == null && this.endPad != null) { if (box.collide(this.endPad.finishBounds)) { var padUp = this.endPad.getAbsPos().up(); padUp = padUp.multiply(10); diff --git a/src/Mission.hx b/src/Mission.hx index 7efc37eb..711d64e2 100644 --- a/src/Mission.hx +++ b/src/Mission.hx @@ -41,6 +41,7 @@ class Mission { public var game:String; public var hasEgg:Bool; public var isCustom:Bool; + public var gameMode:String; #if hl public var addedAt:Int64; #end @@ -116,6 +117,7 @@ class Mission { } mission.type = missionInfo.type.toLowerCase(); mission.missionInfo = missionInfo; + mission.gameMode = missionInfo.gamemode; return mission; } diff --git a/src/MissionList.hx b/src/MissionList.hx index a6d138aa..61f78be8 100644 --- a/src/MissionList.hx +++ b/src/MissionList.hx @@ -66,6 +66,7 @@ class MissionList { var goldMissions:Map> = []; var platinumMissions:Map> = []; var ultraMissions:Map> = []; + var multiplayerMissions:Map> = []; goldMissions.set("beginner", parseDifficulty("gold", "missions_mbg", "beginner")); goldMissions.set("intermediate", parseDifficulty("gold", "missions_mbg", "intermediate")); @@ -80,6 +81,10 @@ class MissionList { ultraMissions.set("intermediate", parseDifficulty("ultra", "missions_mbu", "intermediate")); ultraMissions.set("advanced", parseDifficulty("ultra", "missions_mbu", "advanced")); + multiplayerMissions.set("beginner", parseDifficulty("multiplayer", "multiplayer/hunt", "beginner")); + multiplayerMissions.set("intermediate", parseDifficulty("multiplayer", "multiplayer/hunt", "intermediate")); + multiplayerMissions.set("advanced", parseDifficulty("multiplayer", "multiplayer/hunt", "advanced")); + customMissions = parseDifficulty("custom", "missions", "custom"); @:privateAccess goldMissions["beginner"][goldMissions["beginner"].length - 1].next = goldMissions["intermediate"][0]; @@ -99,6 +104,7 @@ class MissionList { missionList.set("gold", goldMissions); missionList.set("platinum", platinumMissions); missionList.set("ultra", ultraMissions); + missionList.set("multiplayer", multiplayerMissions); Console.log("Loaded MissionList"); Console.log("Gold Beginner: " + goldMissions["beginner"].length); @@ -111,6 +117,9 @@ class MissionList { Console.log("Ultra Beginner: " + ultraMissions["beginner"].length); Console.log("Ultra Intermediate: " + ultraMissions["intermediate"].length); Console.log("Ultra Advanced: " + ultraMissions["advanced"].length); + Console.log("Multiplayer Beginner: " + multiplayerMissions["beginner"].length); + Console.log("Multiplayer Intermediate: " + multiplayerMissions["intermediate"].length); + Console.log("Multiplayer Advanced: " + multiplayerMissions["advanced"].length); Console.log("Custom: " + customMissions.length); // parseCLAList(); diff --git a/src/RandomLCG.hx b/src/RandomLCG.hx new file mode 100644 index 00000000..962564cf --- /dev/null +++ b/src/RandomLCG.hx @@ -0,0 +1,53 @@ +class RandomLCG { + var seed:Int; + + static var msSeed:Int = 1376312589; + + static var quotient = 127773; + static var remainder = 2836; + + public function new(seed = -1) { + this.seed = (seed == -1) ? generateSeed() : seed; + } + + inline function generateSeed() { + // A very, VERY crude LCG but good enough to generate + // a nice range of seed values + msSeed = (msSeed * 0x015a4e35) + 1; + msSeed = (msSeed >> 16) & 0x7fff; + return (msSeed); + } + + public function setSeed(seed:Int) { + this.seed = seed; + } + + public function randInt() { + if (seed <= quotient) + seed = (seed * 16807) % 2147483647; + else { + var high_part:Int = Std.int(seed / quotient); + var low_part = seed % quotient; + + var test:Int = (16807 * low_part) - (remainder * high_part); + + if (test > 0) + seed = test; + else + seed = test + 2147483647; + } + return seed; + } + + public function randFloat() { + return randInt() / 2147483647.0; + } + + public function randRange(i:Int, n:Int) { + return (i + (randInt() % (n - i + 1))); + } + + public function randRangeF(i:Float, n:Int) { + return (i + (n - i) * randFloat()); + } +} diff --git a/src/gui/JoinServerGui.hx b/src/gui/JoinServerGui.hx new file mode 100644 index 00000000..d2554391 --- /dev/null +++ b/src/gui/JoinServerGui.hx @@ -0,0 +1,113 @@ +package gui; + +import h2d.filter.DropShadow; +import hxd.res.BitmapFont; +import src.MarbleGame; +import src.ResourceLoader; +import h3d.Vector; +import src.Util; +import src.Settings; + +class JoinServerGui extends GuiImage { + public function new() { + function chooseBg() { + var rand = Math.random(); + if (rand >= 0 && rand <= 0.244) + return ResourceLoader.getImage('data/ui/backgrounds/gold/${cast (Math.floor(Util.lerp(1, 12, Math.random())), Int)}.jpg'); + if (rand > 0.244 && rand <= 0.816) + return ResourceLoader.getImage('data/ui/backgrounds/platinum/${cast (Math.floor(Util.lerp(1, 28, Math.random())), Int)}.jpg'); + return ResourceLoader.getImage('data/ui/backgrounds/ultra/${cast (Math.floor(Util.lerp(1, 9, Math.random())), Int)}.jpg'); + } + var img = chooseBg(); + super(img.resource.toTile()); + + 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(); + return [normal, hover, pressed]; + } + + this.horizSizing = Width; + this.vertSizing = Height; + this.position = new Vector(); + this.extent = new Vector(640, 480); + + var window = new GuiImage(ResourceLoader.getResource("data/ui/mp/join/window.png", ResourceLoader.getImage, this.imageResources).toTile()); + window.horizSizing = Center; + window.vertSizing = Center; + window.position = new Vector(-60, 5); + window.extent = new Vector(759, 469); + + var hostBtn = new GuiButton(loadButtonImages("data/ui/mp/join/host")); + hostBtn.position = new Vector(521, 379); + hostBtn.extent = new Vector(93, 45); + hostBtn.pressedAction = (e) -> { + MarbleGame.canvas.setContent(new MPPlayMissionGui()); + } + window.addChild(hostBtn); + + var joinBtn = new GuiButton(loadButtonImages("data/ui/mp/join/join")); + joinBtn.position = new Vector(628, 379); + joinBtn.extent = new Vector(93, 45); + window.addChild(joinBtn); + + var refreshBtn = new GuiButton(loadButtonImages("data/ui/mp/join/refresh/refresh-1")); + refreshBtn.position = new Vector(126, 379); + refreshBtn.extent = new Vector(45, 45); + window.addChild(refreshBtn); + + var serverSettingsBtn = new GuiButton(loadButtonImages("data/ui/mp/play/settings")); + serverSettingsBtn.position = new Vector(171, 379); + serverSettingsBtn.extent = new Vector(45, 45); + window.addChild(serverSettingsBtn); + + var exitBtn = new GuiButton(loadButtonImages("data/ui/mp/join/leave")); + exitBtn.position = new Vector(32, 379); + exitBtn.extent = new Vector(93, 45); + exitBtn.pressedAction = (e) -> { + MarbleGame.canvas.setContent(new MainMenuGui()); + } + window.addChild(exitBtn); + + 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 markerFelt18 = markerFelt32b.toSdfFont(cast 14 * Settings.uiScale, MultiChannel); + + function mlFontLoader(text:String) { + switch (text) { + case "MarkerFelt32": + return markerFelt32; + case "MarkerFelt24": + return markerFelt24; + case "MarkerFelt18": + return markerFelt18; + default: + return null; + } + } + + var titleText = new GuiText(markerFelt32); + titleText.position = new Vector(30, 20); + titleText.extent = new Vector(647, 30); + titleText.justify = Center; + titleText.text.text = "Join Server"; + titleText.text.filter = new DropShadow(1.414, 0.785, 0, 1, 0, 0.4, 1, true); + titleText.text.textColor = 0xFFFFFF; + window.addChild(titleText); + + var serverInfoHeader = new GuiText(markerFelt24); + serverInfoHeader.position = new Vector(520, 58); + serverInfoHeader.extent = new Vector(210, 166); + serverInfoHeader.justify = Center; + serverInfoHeader.text.text = "Select a Server"; + serverInfoHeader.text.filter = new DropShadow(1.414, 0.785, 0, 1, 0, 0.4, 1, true); + serverInfoHeader.text.textColor = 0xFFFFFF; + window.addChild(serverInfoHeader); + + this.addChild(window); + } +} diff --git a/src/gui/MPPlayMissionGui.hx b/src/gui/MPPlayMissionGui.hx new file mode 100644 index 00000000..a1b08326 --- /dev/null +++ b/src/gui/MPPlayMissionGui.hx @@ -0,0 +1,507 @@ +package gui; + +import h2d.Scene; +import hxd.Key; +import gui.GuiControl.MouseState; +import h2d.Tile; +import hxd.BitmapData; +import h2d.filter.DropShadow; +import hxd.res.BitmapFont; +import src.MarbleGame; +import src.ResourceLoader; +import h3d.Vector; +import src.Util; +import src.Settings; +import src.Mission; + +class MPPlayMissionGui extends GuiImage { + static var currentSelectionStatic:Int = -1; + static var currentCategoryStatic:String = "beginner"; + + var currentSelection:Int = 0; + var currentCategory:String = "beginner"; + var currentList:Array; + var setSelectedFunc:Int->Void; + var setScoreHover:Bool->Void; + var setCategoryFunc:(String, ?String, ?Bool) -> Void; + var buttonHoldFunc:(dt:Float, mouseState:MouseState) -> Void; + + var buttonCooldown:Float = 0.5; + var maxButtonCooldown:Float = 0.5; + + #if js + var previewTimeoutHandle:Option = None; + #end + #if hl + var previewToken:Int = 0; + #end + + public function new() { + MissionList.buildMissionList(); + function chooseBg() { + var rand = Math.random(); + if (rand >= 0 && rand <= 0.244) + return ResourceLoader.getImage('data/ui/backgrounds/gold/${cast (Math.floor(Util.lerp(1, 12, Math.random())), Int)}.jpg'); + if (rand > 0.244 && rand <= 0.816) + return ResourceLoader.getImage('data/ui/backgrounds/platinum/${cast (Math.floor(Util.lerp(1, 28, Math.random())), Int)}.jpg'); + return ResourceLoader.getImage('data/ui/backgrounds/ultra/${cast (Math.floor(Util.lerp(1, 9, Math.random())), Int)}.jpg'); + } + var img = chooseBg(); + super(img.resource.toTile()); + + if (currentSelectionStatic == -1) { + currentSelectionStatic = 0; + } + + // currentSelection = PlayMissionGui.currentSelectionStatic; + currentCategory = PlayMissionGui.currentCategoryStatic; + + MarbleGame.instance.toRecord = false; + + 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(); + return [normal, hover, pressed]; + } + + function loadButtonImagesExt(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 domcasual24fontdata = ResourceLoader.getFileEntry("data/font/DomCasualD.fnt"); + var domcasual24b = new BitmapFont(domcasual24fontdata.entry); + @:privateAccess domcasual24b.loader = ResourceLoader.loader; + var domcasual24 = domcasual24b.toSdfFont(cast 20 * Settings.uiScale, MultiChannel); + + var domcasual32 = domcasual24b.toSdfFont(cast 26 * Settings.uiScale, MultiChannel); + + var arial14fontdata = ResourceLoader.getFileEntry("data/font/arial.fnt"); + var arial14b = new BitmapFont(arial14fontdata.entry); + @:privateAccess arial14b.loader = ResourceLoader.loader; + var arial14 = arial14b.toSdfFont(cast 12 * Settings.uiScale, MultiChannel); + + var arialb14fontdata = ResourceLoader.getFileEntry("data/font/Arial Bold.fnt"); + var arialb14b = new BitmapFont(arialb14fontdata.entry); + @:privateAccess arialb14b.loader = ResourceLoader.loader; + var arialBold14 = arialb14b.toSdfFont(cast 12 * Settings.uiScale, MultiChannel); + + 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 20 * Settings.uiScale, MultiChannel); + var markerFelt20 = markerFelt32b.toSdfFont(cast 18.5 * Settings.uiScale, MultiChannel); + var markerFelt18 = markerFelt32b.toSdfFont(cast 17 * Settings.uiScale, MultiChannel); + var markerFelt26 = markerFelt32b.toSdfFont(cast 22 * Settings.uiScale, MultiChannel); + + function mlFontLoader(text:String) { + switch (text) { + case "DomCasual24": + return domcasual24; + case "Arial14": + return arial14; + case "ArialBold14": + return arialBold14; + case "MarkerFelt32": + return markerFelt32; + case "MarkerFelt24": + return markerFelt24; + case "MarkerFelt18": + return markerFelt18; + case "MarkerFelt20": + return markerFelt20; + case "MarkerFelt26": + return markerFelt26; + default: + return null; + } + } + + this.horizSizing = Width; + this.vertSizing = Height; + this.position = new Vector(); + this.extent = new Vector(640, 480); + + var window = new GuiImage(ResourceLoader.getResource("data/ui/mp/play/window.png", ResourceLoader.getImage, this.imageResources).toTile()); + window.horizSizing = Center; + window.vertSizing = Center; + window.position = new Vector(-60, 5); + window.extent = new Vector(800, 600); + + var leaveBtn = new GuiButton(loadButtonImages("data/ui/mp/play/leave")); + leaveBtn.position = new Vector(59, 514); + leaveBtn.extent = new Vector(93, 44); + leaveBtn.pressedAction = (e) -> { + MarbleGame.canvas.setContent(new JoinServerGui()); + } + window.addChild(leaveBtn); + + var searchBtn = new GuiButton(loadButtonImages("data/ui/mp/play/search")); + searchBtn.position = new Vector(255, 514); + searchBtn.extent = new Vector(44, 44); + window.addChild(searchBtn); + + var kickBtn = new GuiButton(loadButtonImages("data/ui/mp/play/kick")); + kickBtn.position = new Vector(304, 514); + kickBtn.extent = new Vector(44, 44); + window.addChild(kickBtn); + + var serverSettingsBtn = new GuiButton(loadButtonImages("data/ui/mp/play/settings")); + serverSettingsBtn.position = new Vector(157, 514); + serverSettingsBtn.extent = new Vector(44, 44); + window.addChild(serverSettingsBtn); + + var marbleSelectBtn = new GuiButton(loadButtonImages("data/ui/mp/play/marble")); + marbleSelectBtn.position = new Vector(206, 514); + marbleSelectBtn.extent = new Vector(44, 44); + window.addChild(marbleSelectBtn); + + var temprev = new BitmapData(1, 1); + temprev.setPixel(0, 0, 0); + var tmpprevtile = Tile.fromBitmap(temprev); + + var pmPreview = new GuiImage(tmpprevtile); + pmPreview.position = new Vector(485, 44); + pmPreview.extent = new Vector(248, 187); + window.addChild(pmPreview); + + var difficultyPopover = new GuiControl(); + difficultyPopover.horizSizing = Width; + difficultyPopover.vertSizing = Height; + difficultyPopover.position = new Vector(); + difficultyPopover.extent = new Vector(640, 480); + + var difficultyPopoverInner = new GuiImage(tmpprevtile); + difficultyPopoverInner.horizSizing = Center; + difficultyPopoverInner.vertSizing = Center; + difficultyPopoverInner.position = new Vector(); + difficultyPopoverInner.extent = new Vector(800, 600); + difficultyPopoverInner.pressedAction = (e) -> { + MarbleGame.canvas.popDialog(difficultyPopover, false); + } + difficultyPopover.addChild(difficultyPopoverInner); + + var difficultySelector = new GuiButton(loadButtonImages("data/ui/mp/play/difficulty_beginner")); + difficultySelector.position = new Vector(161, 47); + difficultySelector.extent = new Vector(204, 44); + difficultySelector.pressedAction = (e) -> { + MarbleGame.canvas.pushDialog(difficultyPopover); + }; + window.addChild(difficultySelector); + + var difficultyCloseButton = new GuiButton(loadButtonImages("data/ui/mp/play/difficultymenu")); + difficultyCloseButton.position = new Vector(129, 61); + difficultyCloseButton.extent = new Vector(268, 193); + difficultyPopoverInner.addChild(difficultyCloseButton); + + var catFuncBuilder = (cat:String) -> { + return () -> { + currentList = MissionList.missionList["multiplayer"][cat]; + currentCategory = cat; + setCategoryFunc(cat); + } + } + var beginnerFn = catFuncBuilder("beginner"); + var intermediateFn = catFuncBuilder("intermediate"); + var advancedFn = catFuncBuilder("advanced"); + var customFn = catFuncBuilder("custom"); + + var difficulty0 = new GuiButtonText(loadButtonImages("data/ui/mp/play/difficultysel"), markerFelt24); + difficulty0.position = new Vector(43, 42); + difficulty0.ratio = -1 / 16; + difficulty0.setExtent(new Vector(180, 31)); + difficulty0.txtCtrl.text.text = "Intermediate"; + difficulty0.pressedAction = (e) -> { + intermediateFn(); + } + difficultyCloseButton.addChild(difficulty0); + + var difficulty1 = new GuiButtonText(loadButtonImages("data/ui/mp/play/difficultysel"), markerFelt24); + difficulty1.position = new Vector(43, 72); + difficulty1.ratio = -1 / 16; + difficulty1.setExtent(new Vector(180, 31)); + difficulty1.txtCtrl.text.text = "Advanced"; + difficulty1.pressedAction = (e) -> { + advancedFn(); + } + difficultyCloseButton.addChild(difficulty1); + + var difficulty2 = new GuiButtonText(loadButtonImages("data/ui/mp/play/difficultysel"), markerFelt24); + difficulty2.position = new Vector(43, 116); + difficulty2.ratio = -1 / 16; + difficulty2.setExtent(new Vector(180, 31)); + difficulty2.txtCtrl.text.text = "Custom"; + difficulty2.pressedAction = (e) -> { + customFn(); + } + difficultyCloseButton.addChild(difficulty2); + + var pmPreviewFrame = new GuiImage(ResourceLoader.getResource('data/ui/mp/play/levelframe.png', ResourceLoader.getImage, this.imageResources).toTile()); + pmPreviewFrame.position = new Vector(0, 0); + pmPreviewFrame.extent = new Vector(248, 187); + pmPreview.addChild(pmPreviewFrame); + + var prevBtn = new GuiButton(loadButtonImagesExt("data/ui/mp/play/prev")); + prevBtn.position = new Vector(491, 514); + prevBtn.extent = new Vector(73, 44); + prevBtn.gamepadAccelerator = ["dpadLeft"]; + prevBtn.pressedAction = (sender) -> { + setSelectedFunc(currentSelection - 1); + } + window.addChild(prevBtn); + + var nextBtn = new GuiButton(loadButtonImagesExt("data/ui/mp/play/next")); + nextBtn.position = new Vector(659, 514); + nextBtn.extent = new Vector(73, 44); + nextBtn.gamepadAccelerator = ["dpadRight"]; + nextBtn.pressedAction = (sender) -> { + setSelectedFunc(currentSelection + 1); + } + window.addChild(nextBtn); + + var playBtn = new GuiButton(loadButtonImages("data/ui/mp/play/play")); + playBtn.position = new Vector(565, 514); + playBtn.extent = new Vector(93, 44); + playBtn.pressedAction = (sender) -> { + MarbleGame.instance.playMission(currentList[currentSelection]); + } + window.addChild(playBtn); + + var pmDescContainer = new GuiControl(); + pmDescContainer.position = new Vector(43, 99); + pmDescContainer.extent = new Vector(427, 99); + window.addChild(pmDescContainer); + + var pmDesc = new GuiMLText(markerFelt18, mlFontLoader); + pmDesc.position = new Vector(0, 0); + pmDesc.extent = new Vector(427, 99); + pmDesc.text.filter = new DropShadow(1.414, 0.785, 0x0000000F, 1, 0, 0.4, 1, true); + pmDesc.text.lineSpacing = -1; + pmDescContainer.addChild(pmDesc); + + var parTime = new GuiMLText(markerFelt18, mlFontLoader); + parTime.position = new Vector(43, 190); + parTime.extent = new Vector(416, 44); + parTime.text.filter = new DropShadow(1.414, 0.785, 0x0000000F, 1, 0, 0.4, 1, true); + parTime.text.lineSpacing = -1; + window.addChild(parTime); + + var playersBox = new GuiControl(); + playersBox.position = new Vector(463, 279); + playersBox.extent = new Vector(305, 229); + window.addChild(playersBox); + + var playerListTitle = new GuiText(markerFelt24); + playerListTitle.position = new Vector(7, 0); + playerListTitle.extent = new Vector(275, 22); + playerListTitle.text.text = "Players"; + playerListTitle.text.textColor = 0xBDCFE4; + playerListTitle.justify = Center; + playerListTitle.text.filter = new DropShadow(1.414, 0.785, 0x0000000F, 1, 0, 0.4, 1, true); + playersBox.addChild(playerListTitle); + + this.addChild(window); + + buttonHoldFunc = (dt:Float, mouseState:MouseState) -> { + var prevBox = prevBtn.getRenderRectangle(); + var nextBox = nextBtn.getRenderRectangle(); + + if (prevBox.inRect(mouseState.position) && mouseState.button == Key.MOUSE_LEFT) { + if (buttonCooldown <= 0) { + prevBtn.pressedAction(new GuiEvent(prevBtn)); + buttonCooldown = maxButtonCooldown; + maxButtonCooldown *= 0.75; + } + } + + if (nextBox.inRect(mouseState.position) && mouseState.button == Key.MOUSE_LEFT) { + if (buttonCooldown <= 0) { + nextBtn.pressedAction(new GuiEvent(nextBtn)); + buttonCooldown = maxButtonCooldown; + maxButtonCooldown *= 0.75; + } + } + + if (buttonCooldown > 0 && mouseState.button == Key.MOUSE_LEFT) + buttonCooldown -= dt; + + if (mouseState.button != Key.MOUSE_LEFT) { + maxButtonCooldown = 0.5; + buttonCooldown = maxButtonCooldown; + } + } + + setCategoryFunc = function(category:String, ?sort:String = null, ?doRender:Bool = true) { + currentList = MissionList.missionList["multiplayer"][category]; + + @:privateAccess difficultySelector.anim.frames = loadButtonImages('data/ui/mp/play/difficulty_${category}'); + + if (category == "beginner") { + difficulty0.txtCtrl.text.text = "Intermediate"; + difficulty1.txtCtrl.text.text = "Advanced"; + difficulty2.txtCtrl.text.text = "Custom"; + difficulty0.pressedAction = (e) -> { + intermediateFn(); + } + difficulty1.pressedAction = (e) -> { + advancedFn(); + } + difficulty2.pressedAction = (e) -> { + customFn(); + } + } + if (category == "intermediate") { + difficulty0.txtCtrl.text.text = "Beginner"; + difficulty1.txtCtrl.text.text = "Advanced"; + difficulty2.txtCtrl.text.text = "Custom"; + difficulty0.pressedAction = (e) -> { + beginnerFn(); + } + difficulty1.pressedAction = (e) -> { + advancedFn(); + } + difficulty2.pressedAction = (e) -> { + customFn(); + } + } + if (category == "custom") { + difficulty0.txtCtrl.text.text = "Beginner"; + difficulty1.txtCtrl.text.text = "Intermediate"; + difficulty2.txtCtrl.text.text = "Advanced"; + difficulty0.pressedAction = (e) -> { + beginnerFn(); + } + difficulty1.pressedAction = (e) -> { + intermediateFn(); + } + difficulty2.pressedAction = (e) -> { + advancedFn(); + } + } + + if (sort != null) { + currentList = currentList.copy(); // Don't modify the originals + if (sort == "alpha") { + currentList.sort((x, y) -> x.title > y.title ? 1 : (x.title < y.title ? -1 : 0)); + } + if (sort == "date") { + currentList.sort((x, y) -> x.addedAt > y.addedAt ? 1 : (x.addedAt < y.addedAt ? -1 : 0)); + } + } + + currentCategoryStatic = currentCategory; + + setSelectedFunc(currentList.length - 1); + // if (doRender) + // this.render(cast(this.parent, Canvas).scene2d); + } + + setSelectedFunc = function setSelected(index:Int) { + if (index > currentList.length - 1) { + index = currentList.length - 1; + } + if (index < 0) { + index = 0; + } + + currentSelection = index; + currentSelectionStatic = currentSelection; + + var currentMission = currentList[currentSelection]; + + if (index == 0) { + prevBtn.disabled = true; + } else + prevBtn.disabled = false; + if (index == Math.max(currentList.length - 1, 0)) { + nextBtn.disabled = true; + } else + nextBtn.disabled = false; + + // if (currentCategory != "custom" + // && Settings.progression[["beginner", "intermediate", "advanced", "expert"].indexOf(currentCategory)] < currentSelection) { + // noQualText.text.visible = true; + // filt.matrix.identity(); + // filt.matrix.colorGain(0, 96 / 255); + // pmPlay.disabled = true; + // } else { + playBtn.disabled = false; + // } + + if (currentMission == null) { + currentMission = new Mission(); + currentMission.title = ""; + currentMission.description = ""; + currentMission.path = "bruh"; + currentSelection = -1; + } + + pmDesc.text.text = '

#${currentSelection + 1}: ${currentMission.title}

' + + '${currentMission.description}'; + + parTime.text.text = 'Duration: ${Util.formatTime(currentMission.qualifyTime)}
' + + 'Author: ${currentMission.artist}'; + + // pmPreview.bmp.tile = tmpprevtile; + #if js + switch (previewTimeoutHandle) { + case None: + previewTimeoutHandle = Some(js.Browser.window.setTimeout(() -> { + var prevpath = currentMission.getPreviewImage(prevImg -> { + pmPreview.bmp.tile = prevImg; + }); + if (prevpath != pmPreview.bmp.tile.getTexture().name) { + pmPreview.bmp.tile = tmpprevtile; + } + }, 75)); + case Some(previewTimeoutHandle_id): + js.Browser.window.clearTimeout(previewTimeoutHandle_id); + previewTimeoutHandle = Some(js.Browser.window.setTimeout(() -> { + var prevpath = currentMission.getPreviewImage(prevImg -> { + pmPreview.bmp.tile = prevImg; + }); + if (prevpath != pmPreview.bmp.tile.getTexture().name) { + pmPreview.bmp.tile = tmpprevtile; + } + }, 75)); + } + #end + #if hl + var pTok = previewToken++; + var prevpath = currentMission.getPreviewImage(prevImg -> { + if (pTok + 1 != previewToken) + return; + pmPreview.bmp.tile = prevImg; + }); // Shit be sync + if (prevpath != pmPreview.bmp.tile.getTexture().name) { + pmPreview.bmp.tile = tmpprevtile; + } + #end + } + + currentList = MissionList.missionList["multiplayer"]["beginner"]; + + setCategoryFunc(currentCategoryStatic, null, false); + } + + public override function render(scene2d:Scene, ?parent:h2d.Flow) { + super.render(scene2d, parent); + setSelectedFunc(currentSelectionStatic); + } + + public override function update(dt:Float, mouseState:MouseState) { + super.update(dt, mouseState); + + buttonHoldFunc(dt, mouseState); + + if (Key.isPressed(Key.LEFT)) + setSelectedFunc(currentSelection - 1); + if (Key.isPressed(Key.RIGHT)) + setSelectedFunc(currentSelection + 1); + } +} diff --git a/src/gui/MainMenuGui.hx b/src/gui/MainMenuGui.hx index 8dff8351..72d6c193 100644 --- a/src/gui/MainMenuGui.hx +++ b/src/gui/MainMenuGui.hx @@ -80,9 +80,12 @@ class MainMenuGui extends GuiImage { } mainMenuContent.addChild(playButton); - var lbButton = new GuiImage(ResourceLoader.getResource('data/ui/menu/online_i.png', ResourceLoader.getImage, this.imageResources).toTile()); + var lbButton = new GuiButton(loadButtonImages("data/ui/menu/online")); lbButton.position = new Vector(-5, 128); lbButton.extent = new Vector(247, 164); + lbButton.pressedAction = (sender) -> { + MarbleGame.canvas.setContent(new JoinServerGui()); + } mainMenuContent.addChild(lbButton); var optionsButton = new GuiButton(loadButtonImages("data/ui/menu/options")); diff --git a/src/mis/MissionElement.hx b/src/mis/MissionElement.hx index 2b3a0b5c..c54ee1a7 100644 --- a/src/mis/MissionElement.hx +++ b/src/mis/MissionElement.hx @@ -58,6 +58,10 @@ class MissionElementScriptObject extends MissionElementBase { var music:String; var alarmstarttime:String; var game:String; + var gamemode:String; + var maxgemsperspawn:String; + var radiusfromgem:String; + var spawnblock:String; public function new() { _type = MissionElementType.ScriptObject; diff --git a/src/modes/GameMode.hx b/src/modes/GameMode.hx index e7681f1e..e81008c9 100644 --- a/src/modes/GameMode.hx +++ b/src/modes/GameMode.hx @@ -32,6 +32,11 @@ interface GameMode { class GameModeFactory { public static function getGameMode(level:MarbleWorld, mode:String):GameMode { + if (mode != null) { + if (mode.toLowerCase() == "hunt") { + return new HuntMode(level); + } + } return new NullMode(level); } } diff --git a/src/modes/HuntMode.hx b/src/modes/HuntMode.hx new file mode 100644 index 00000000..cedb8119 --- /dev/null +++ b/src/modes/HuntMode.hx @@ -0,0 +1,356 @@ +package modes; + +import octree.IOctreeObject; +import octree.IOctreeObject.RayIntersectionData; +import h3d.col.Bounds; +import octree.IOctreeElement; +import shapes.GemBeam; +import h3d.Quat; +import h3d.Vector; +import shapes.Gem; +import mis.MisParser; +import mis.MissionElement.MissionElementSimGroup; +import octree.Octree; +import mis.MissionElement.MissionElementTrigger; +import mis.MissionElement.MissionElementType; +import src.Mission; +import src.Marble; +import src.AudioManager; +import src.ResourceLoader; + +@:structInit +@:publicFields +class GemSpawnPoint implements IOctreeObject { + var gem:Gem; + var gemBeam:GemBeam; + + var boundingBox:Bounds; + var netIndex:Int; + + var priority:Int; + + public function new(vec:Vector, spawn:Gem, netIndex:Int) { + boundingBox = new Bounds(); + boundingBox.addPoint(vec.add(new Vector(-0.5, -0.5, -0.5)).toPoint()); + boundingBox.addPoint(vec.add(new Vector(0.5, 0.5, 0.5)).toPoint()); + this.gem = spawn; + this.netIndex = netIndex; + } + + public function getElementType() { + return 2; + } + + public function setPriority(priority:Int) { + this.priority = priority; + } + + public function rayCast(rayOrigin:Vector, rayDirection:Vector, resultSet:Array) { + throw new haxe.exceptions.NotImplementedException(); // Not applicable + } +} + +class HuntMode extends NullMode { + var playerSpawnPoints:Array = []; + var spawnPointTaken = []; + var gemOctree:Octree; + var gemGroupRadius:Float; + var maxGemsPerGroup:Int; + var rng:RandomLCG = new RandomLCG(100); + var rng2:RandomLCG = new RandomLCG(100); + var gemSpawnPoints:Array; + var lastSpawn:GemSpawnPoint; + var activeGemSpawnGroup:Array; + var gemBeams:Array = []; + var gemToBeamMap:Map = []; + var activeGems:Array = []; + var points:Int = 0; + + override function missionScan(mission:Mission) { + function scanMission(simGroup:MissionElementSimGroup) { + for (element in simGroup.elements) { + if ([MissionElementType.Trigger].contains(element._type)) { + var spawnSphere:MissionElementTrigger = cast element; + var dbname = spawnSphere.datablock.toLowerCase(); + if (dbname == "spawntrigger") { + playerSpawnPoints.push(spawnSphere); + spawnPointTaken.push(false); + } + } else if (element._type == MissionElementType.SimGroup) { + scanMission(cast element); + } + } + } + scanMission(mission.root); + }; + + override function getSpawnTransform() { + var idx = Math.floor(rng2.randRange(0, playerSpawnPoints.length - 1)); + while (spawnPointTaken[idx]) { + idx = Math.floor(rng2.randRange(0, playerSpawnPoints.length - 1)); + } + spawnPointTaken[idx] = true; + var randomSpawn = playerSpawnPoints[idx]; + var spawnPos = MisParser.parseVector3(randomSpawn.position); + spawnPos.x *= -1; + var spawnRot = MisParser.parseRotation(randomSpawn.rotation); + spawnRot.x *= -1; + spawnRot.w *= -1; + var spawnMat = spawnRot.toMatrix(); + var up = spawnMat.up(); + spawnPos = spawnPos.add(up); // 1.5 -> 0.5 + return { + position: spawnPos, + orientation: spawnRot, + up: up + } + } + + override function getRespawnTransform(marble:Marble) { + var lastContactPos = marble.lastContactPosition; + if (lastContactPos == null) { + return getSpawnTransform(); + } + // Pick closest spawn point + var closestSpawn:MissionElementTrigger = null; + var closestDistance = 1e10; + for (spawn in playerSpawnPoints) { + var pos = MisParser.parseVector3(spawn.position); + pos.x *= -1; + var dist = pos.distance(lastContactPos); + if (dist < closestDistance) { + closestDistance = dist; + closestSpawn = spawn; + } + } + if (closestSpawn != null) { + var spawnPos = MisParser.parseVector3(closestSpawn.position); + spawnPos.x *= -1; + var spawnRot = MisParser.parseRotation(closestSpawn.rotation); + spawnRot.x *= -1; + spawnRot.w *= -1; + var spawnMat = spawnRot.toMatrix(); + var up = spawnMat.up(); + spawnPos = spawnPos.add(up); // 1.5 -> 0.5 + + return { + position: spawnPos, + orientation: spawnRot, + up: up + } + } + return null; + } + + function setupGems() { + hideExisting(); + this.activeGems = []; + this.activeGemSpawnGroup = []; + if (this.gemSpawnPoints == null) { + this.gemOctree = new Octree(); + this.gemSpawnPoints = []; + for (gem in this.level.gems) { + var spawn:GemSpawnPoint = new GemSpawnPoint(gem.getAbsPos().getPosition(), gem, gemSpawnPoints.length); + gem.setHide(true); + gem.pickedUp = true; + this.gemSpawnPoints.push(spawn); + this.gemOctree.insert(spawn); + gem.setHide(true); + } + } + spawnHuntGems(); + } + + function spawnHuntGems() { + if (activeGems.length != 0) + return; + var gemGroupRadius = 15.0; + var maxGemsPerSpawn = 7; + if (level.mission.missionInfo.maxgemsperspawn != null && level.mission.missionInfo.maxgemsperspawn != "") + maxGemsPerSpawn = Std.parseInt(level.mission.missionInfo.maxgemsperspawn); + if (level.mission.missionInfo.radiusfromgem != null && level.mission.missionInfo.radiusfromgem != "") + gemGroupRadius = Std.parseFloat(level.mission.missionInfo.radiusfromgem); + var spawnBlock = gemGroupRadius * 2; + if (level.mission.missionInfo.spawnblock != null && level.mission.missionInfo.spawnblock != "") + spawnBlock = Std.parseFloat(level.mission.missionInfo.spawnblock); + + var lastPos = null; + if (lastSpawn != null) + lastPos = lastSpawn.gem.getAbsPos().getPosition(); + + var furthestDist = 0.0; + var furthest = null; + + for (i in 0...6) { + var gem = gemSpawnPoints[rng.randRange(0, gemSpawnPoints.length - 1)]; + if (lastPos != null) { + var dist = gem.gem.getAbsPos().getPosition().distance(lastPos); + if (dist < spawnBlock) { + if (dist > furthestDist) { + furthestDist = dist; + furthest = gem; + } + continue; + } else { + break; + } + } else { + furthest = gem; + break; + } + } + if (furthest == null) { + furthest = gemSpawnPoints[rng.randRange(0, gemSpawnPoints.length - 1)]; + } + var pos = furthest.gem.getAbsPos().getPosition(); + + var results = []; + var search = gemOctree.radiusSearch(pos, gemGroupRadius); + for (elem in search) { + var gemElem:GemSpawnPoint = cast elem; + var gemPos = gemElem.gem.getAbsPos().getPosition(); + results.push({ + gem: gemElem.netIndex, + weight: this.gemGroupRadius - gemPos.distance(pos) + rng.randRange(0, getGemWeight(gemElem.gem) + 3) + }); + } + results.sort((a, b) -> { + if (a.weight > b.weight) + return -1; + if (a.weight < b.weight) + return 1; + return 0; + }); + var spawnSet = results.slice(0, maxGemsPerSpawn).map(x -> x.gem); + for (gem in spawnSet) { + spawnGem(gem); + } + activeGemSpawnGroup = spawnSet; + + lastSpawn = furthest; + } + + function spawnGem(spawn:Int) { + var gem = gemSpawnPoints[spawn]; + gem.gem.setHide(false); + gem.gem.pickedUp = false; + activeGems.push(gem.gem); + if (gem.gemBeam == null) { + gem.gemBeam = new GemBeam(StringTools.replace(gem.gem.gemColor, '.gem', '')); + + var gemPos = gem.gem.getAbsPos().getPosition(); + + gem.gemBeam.setPosition(gemPos.x, gemPos.y, gemPos.z); + gem.gemBeam.setRotationQuat(gem.gem.getRotationQuat().clone()); + // gem.gemBeam.setOpacity(0.99); + this.gemBeams.push(gem.gemBeam); + + this.gemToBeamMap.set(gem.gem, gem.gemBeam); + + level.addDtsObject(gem.gemBeam, () -> { + // Please be fast lol + }); + } else { + gem.gemBeam.setHide(false); + } + } + + function getGemWeight(gem:Gem) { + if (gem.gemColor == "red") + return 0; + if (gem.gemColor == "yellow") + return 1; + if (gem.gemColor == "blue") + return 4; + return 0; + } + + function hideExisting() { + lastSpawn = null; + if (gemSpawnPoints != null) { + for (gs in gemSpawnPoints) { + gs.gem.setHide(true); + gs.gem.pickedUp = true; + if (gs.gemBeam != null) { + gs.gemBeam.setHide(true); + } + } + } + } + + override public function getStartTime() { + return level.mission.qualifyTime; + } + + override function onRestart() { + setupGems(); + points = 0; + } + + override function onGemPickup(marble:Marble, gem:Gem) { + // if ((@:privateAccess !marble.isNetUpdate && Net.isHost) || !Net.isMP) { + if (marble == level.marble) + AudioManager.playSound(ResourceLoader.getResource('data/sound/gotgem.wav', ResourceLoader.getAudio, @:privateAccess this.level.soundResources)); + else + AudioManager.playSound(ResourceLoader.getResource('data/sound/opponent_gem_collect.wav', ResourceLoader.getAudio, + @:privateAccess this.level.soundResources)); + // } + activeGems.remove(gem); + var beam = gemToBeamMap.get(gem); + beam.setHide(true); + + // if (!this.level.isMultiplayer || Net.isHost) { + spawnHuntGems(); + // } + + var incr = 0; + switch (gem.gemColor) { + case "red.gem": + incr = 1; + case "yellow.gem": + incr = 2; + case "blue.gem": + incr = 5; + } + + if (@:privateAccess !marble.isNetUpdate) { + if (marble == level.marble) { + switch (gem.gemColor) { + case "red.gem": + points += 1; + @:privateAccess level.playGui.addMiddleMessage('+1', 0xFF6666); + case "yellow.gem": + points += 2; + @:privateAccess level.playGui.addMiddleMessage('+2', 0xFFFF66); + case "blue.gem": + points += 5; + @:privateAccess level.playGui.addMiddleMessage('+5', 0x6666FF); + } + // @:privateAccess level.playGui.formatGemHuntCounter(points); + } + } + + // if (this.level.isMultiplayer && Net.isHost) { + // var packet = new GemPickupPacket(); + // packet.clientId = @:privateAccess marble.connection == null ? 0 : @:privateAccess marble.connection.id; + // packet.gemId = gem.netIndex; + // packet.serverTicks = level.timeState.ticks; + // packet.scoreIncr = incr; + // var os = new OutputBitStream(); + // os.writeByte(GemPickup); + // packet.serialize(os); + // Net.sendPacketToIngame(os); + + // Settings.playStatistics.totalMPScore += incr; + + // @:privateAccess level.playGui.incrementPlayerScore(packet.clientId, packet.scoreIncr); + // } + // if (this.level.isMultiplayer && Net.isClient) { + // gem.pickUpClient = @:privateAccess marble.connection == null ? Net.clientId : @:privateAccess marble.connection.id; + // } + } + + override public function timeMultiplier() { + return -1; + } +} diff --git a/src/modes/NullMode.hx b/src/modes/NullMode.hx index f84abd6d..ba0f7bdf 100644 --- a/src/modes/NullMode.hx +++ b/src/modes/NullMode.hx @@ -113,7 +113,7 @@ class NullMode implements GameMode { } public function getPreloadFiles() { - return ['data/sound/gem_all.wav']; + return []; } public function onTimeExpire() {} diff --git a/src/shaders/DtsTexture.hx b/src/shaders/DtsTexture.hx index 0fdd7e92..62f877b6 100644 --- a/src/shaders/DtsTexture.hx +++ b/src/shaders/DtsTexture.hx @@ -16,6 +16,8 @@ class DtsTexture extends hxsl.Shader { @range(0, 1) @param var killAlphaThreshold:Float; @param var texture:Sampler2D; @const var normalizeNormals:Bool; + @const var usePremultipliedAlpha:Bool; + @param var opacityMult:Float; @perInstance @param var currentOpacity:Float; var calculatedUV:Vec2; var pixelColor:Vec4; @@ -40,7 +42,11 @@ class DtsTexture extends hxsl.Shader { pixelColor *= c; if (specularAlpha) specColor *= c.aaa; - pixelColor.a *= c.a * currentOpacity; + if (usePremultipliedAlpha) { + pixelColor.a = c.a * currentOpacity * opacityMult; + } else { + pixelColor.a *= c.a * currentOpacity; + } } } diff --git a/src/shapes/GemBeam.hx b/src/shapes/GemBeam.hx new file mode 100644 index 00000000..a54b6d40 --- /dev/null +++ b/src/shapes/GemBeam.hx @@ -0,0 +1,17 @@ +package shapes; + +import h3d.mat.Material; +import src.DtsObject; +import src.ResourceLoader; + +class GemBeam extends DtsObject { + public function new(color:String) { + super(); + this.dtsPath = "data/shapes/gemlights/gemlight.dts"; + this.isCollideable = false; + this.isTSStatic = false; + this.identifier = "GemBeam" + color; + this.useInstancing = true; + this.matNameOverride.set('base.lightbeam', color + '.lightbeam'); + } +}