diff --git a/src/DifBuilder.hx b/src/DifBuilder.hx index 2ce06a75..4741edc0 100644 --- a/src/DifBuilder.hx +++ b/src/DifBuilder.hx @@ -204,7 +204,8 @@ class DifBuilder { worker.run(); } - static function createNoiseTileMaterial(onFinish:hxsl.Shader->Void, baseTexture:String, noiseSuffix:String, shininess:Float, specular:Vector) { + static function createNoiseTileMaterial(onFinish:hxsl.Shader->Void, baseTexture:String, noiseSuffix:String, shininess:Float, specular:Vector, + uvScale:Float = 1) { var worker = new ResourceLoaderWorker(() -> { var diffuseTex = ResourceLoader.getTexture('data/interiors_mbu/${baseTexture}').resource; diffuseTex.wrap = Repeat; @@ -216,7 +217,7 @@ class DifBuilder { noiseTex.wrap = Repeat; noiseTex.mipMap = Nearest; var shader = new NoiseTileMaterial(diffuseTex, normalTex, noiseTex, shininess, specular, MarbleGame.instance.world.ambient, - MarbleGame.instance.world.dirLight, MarbleGame.instance.world.dirLightDir, 1); + MarbleGame.instance.world.dirLight, MarbleGame.instance.world.dirLightDir, uvScale); onFinish(shader); }); worker.loadFile('interiors_mbu/${baseTexture}'); @@ -244,33 +245,33 @@ class DifBuilder { 'interiors_mbu/plate_1.jpg' => (onFinish) -> createPhongMaterial(onFinish, 'plate.randomize.png', 'plate.normal.png', 8, new Vector(1, 1, 0.8, 1), 0.5), 'interiors_mbu/tile_beginner.png' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_beginner.png', '', 40, new Vector(1, 1, 1, 1)), 'interiors_mbu/tile_beginner_shadow.png' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_beginner.png', '_shadow', 40, - new Vector(0.2, 0.2, 0.2, 0.2)), + new Vector(0.2, 0.2, 0.2, 0.2), 1 / 4), 'interiors_mbu/tile_beginner_red.jpg' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_beginner.png', '_red', 40, new Vector(1, 1, 1, 1)), 'interiors_mbu/tile_beginner_red_shadow.png' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_beginner.png', '_red_shadow', 40, - new Vector(0.2, 0.2, 0.2, 0.2)), + new Vector(0.2, 0.2, 0.2, 0.2), 1 / 4), 'interiors_mbu/tile_beginner_blue.jpg' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_beginner.png', '_blue', 40, new Vector(1, 1, 1, 1)), 'interiors_mbu/tile_beginner_blue_shadow.png' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_beginner.png', '_blue_shadow', 40, - new Vector(0.2, 0.2, 0.2, 0.2)), + new Vector(0.2, 0.2, 0.2, 0.2), 1 / 4), 'interiors_mbu/tile_intermediate.png' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_intermediate.png', '', 40, new Vector(1, 1, 1, 1)), 'interiors_mbu/tile_intermediate_shadow.png' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_intermediate.png', '_shadow', 40, - new Vector(0.2, 0.2, 0.2, 0.2)), + new Vector(0.2, 0.2, 0.2, 0.2), 1 / 4), 'interiors_mbu/tile_intermediate_red.jpg' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_intermediate.png', '_red', 40, new Vector(1, 1, 1, 1)), 'interiors_mbu/tile_intermediate_red_shadow.png' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_intermediate.png', '_red_shadow', 40, - new Vector(0.2, 0.2, 0.2, 0.2)), + new Vector(0.2, 0.2, 0.2, 0.2), 1 / 4), 'interiors_mbu/tile_intermediate_green.jpg' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_intermediate.png', '_green', 40, new Vector(1, 1, 1, 1)), 'interiors_mbu/tile_intermediate_green_shadow.png' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_intermediate.png', '_green_shadow', 40, - new Vector(0.2, 0.2, 0.2, 0.2)), + new Vector(0.2, 0.2, 0.2, 0.2), 1 / 4), 'interiors_mbu/tile_advanced.png' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_advanced.png', '', 40, new Vector(1, 1, 1, 1)), 'interiors_mbu/tile_advanced_shadow.png' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_advanced.png', '_shadow', 40, - new Vector(0.2, 0.2, 0.2, 0.2)), + new Vector(0.2, 0.2, 0.2, 0.2), 1 / 4), 'interiors_mbu/tile_advanced_blue.jpg' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_advanced.png', '_blue', 40, new Vector(1, 1, 1, 1)), 'interiors_mbu/tile_advanced_blue_shadow.png' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_advanced.png', '_blue_shadow', 40, - new Vector(0.2, 0.2, 0.2, 0.2)), + new Vector(0.2, 0.2, 0.2, 0.2), 1 / 4), 'interiors_mbu/tile_advanced_green.jpg' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_advanced.png', '_green', 40, new Vector(1, 1, 1, 1)), 'interiors_mbu/tile_advanced_green_shadow.jpg' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_advanced.png', '_green_shadow', 40, - new Vector(0.2, 0.2, 0.2, 0.2)), + new Vector(0.2, 0.2, 0.2, 0.2), 1 / 4), 'interiors_mbu/tile_underside.png' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_underside.png', '', 40, new Vector(1, 1, 1, 1)), 'interiors_mbu/wall_beginner.png' => (onFinish) -> createPhongMaterial(onFinish, 'wall_beginner.png', 'wall_mbu.normal.png', 12, new Vector(0.8, 0.8, 0.6, 1)), @@ -710,8 +711,12 @@ class DifBuilder { texture.mipMap = Nearest; var exactName = StringTools.replace(texture.name, "data/", ""); material = h3d.mat.Material.create(texture); - if (shaderMaterialDict.exists(exactName)) { - var retrievefunc = shaderMaterialDict[exactName]; + var matDictName = exactName; + if (!shaderMaterialDict.exists(matDictName)) { + matDictName = StringTools.replace(exactName, "multiplayer/interiors/mbu", "interiors_mbu"); + } + if (shaderMaterialDict.exists(matDictName)) { + var retrievefunc = shaderMaterialDict[matDictName]; shaderWorker.addTask(fwd -> { retrievefunc(shad -> { material.mainPass.removeShader(material.textureShader); diff --git a/src/Marble.hx b/src/Marble.hx index 5daeec3d..eecdcf04 100644 --- a/src/Marble.hx +++ b/src/Marble.hx @@ -273,6 +273,7 @@ class Marble extends GameObject { var forcefield:DtsObject; var helicopter:DtsObject; + var megaHelicopter:DtsObject; var superBounceEnableTime:Float = -1e8; var shockAbsorberEnableTime:Float = -1e8; var helicopterEnableTime:Float = -1e8; @@ -554,9 +555,21 @@ class Marble extends GameObject { this.helicopter.y = 1e8; this.helicopter.z = 1e8; + this.megaHelicopter = new DtsObject(); + this.megaHelicopter.dtsPath = "data/shapes/items/megahelicopter.dts"; + this.megaHelicopter.useInstancing = true; + this.megaHelicopter.identifier = "MegaHelicopter"; + this.megaHelicopter.showSequences = true; + this.megaHelicopter.isBoundingBoxCollideable = false; + // this.addChild(this.helicopter); + this.megaHelicopter.x = 1e8; + this.megaHelicopter.y = 1e8; + this.megaHelicopter.z = 1e8; + var worker = new ResourceLoaderWorker(onFinish); worker.addTask(fwd -> level.addDtsObject(this.forcefield, fwd)); worker.addTask(fwd -> level.addDtsObject(this.helicopter, fwd)); + worker.addTask(fwd -> level.addDtsObject(this.megaHelicopter, fwd)); worker.run(); } @@ -1873,6 +1886,7 @@ class Marble extends GameObject { marbleUpdate.netFlags = this.netFlags; marbleUpdate.gravityDirection = this.currentUp; marbleUpdate.serialize(b); + return b.getBytes(); } @@ -1987,7 +2001,7 @@ class Marble extends GameObject { lastMove = move.move; } } - if (move == null && !this.controllable) { + if (move == null && !this.controllable || this.mode == Finish) { var axis = moveMotionDir != null ? moveMotionDir : new Vector(0, -1, 0); var innerMove = lastMove; if (innerMove == null) { @@ -2243,6 +2257,7 @@ class Marble extends GameObject { var shockEnabled = isShockAbsorberEnabled(timeState); var bounceEnabled = isSuperBounceEnabled(timeState); var helicopterEnabled = isHelicopterEnabled(timeState); + var megaEnabled = isMegaMarbleEnabled(timeState); var selfMarble = level.marble == cast this; if (selfMarble) { if (shockEnabled) { @@ -2264,15 +2279,30 @@ class Marble extends GameObject { this.forcefield.y = 1e8; this.forcefield.z = 1e8; } - if (helicopterEnabled) { - this.helicopter.setPosition(x, y, z); - this.helicopter.setRotationQuat(this.level.getOrientationQuat(timeState.currentAttemptTime)); - if (selfMarble) - this.helicopterSound.pause = false; - } else { + if (megaEnabled) { this.helicopter.setPosition(1e8, 1e8, 1e8); - if (selfMarble) - this.helicopterSound.pause = true; + if (helicopterEnabled) { + this.megaHelicopter.setPosition(x, y, z); + this.megaHelicopter.setRotationQuat(this.level.getOrientationQuat(timeState.currentAttemptTime)); + if (selfMarble) + this.helicopterSound.pause = false; + } else { + this.megaHelicopter.setPosition(1e8, 1e8, 1e8); + if (selfMarble) + this.helicopterSound.pause = true; + } + } else { + this.megaHelicopter.setPosition(1e8, 1e8, 1e8); + if (helicopterEnabled) { + this.helicopter.setPosition(x, y, z); + this.helicopter.setRotationQuat(this.level.getOrientationQuat(timeState.currentAttemptTime)); + if (selfMarble) + this.helicopterSound.pause = false; + } else { + this.helicopter.setPosition(1e8, 1e8, 1e8); + if (selfMarble) + this.helicopterSound.pause = true; + } } } diff --git a/src/MarbleWorld.hx b/src/MarbleWorld.hx index ed48917c..a0343469 100644 --- a/src/MarbleWorld.hx +++ b/src/MarbleWorld.hx @@ -874,6 +874,10 @@ class MarbleWorld extends Scheduler { marble.setMode(Play); this.playGui.setCenterText('go'); + + var huntMode = cast(this.gameMode, HuntMode); + + huntMode.freeSpawns(); } } if (this.multiplayerStarted) { @@ -1254,6 +1258,49 @@ class MarbleWorld extends Scheduler { } } + // MP ONLY + public function completeRestart() { + for (id => client in Net.clientIdMap) { + client.state = LOBBY; + client.lobbyReady = false; + } + Net.hostReady = false; + Net.lobbyHostReady = false; + Net.lobbyClientReady = false; + + this.finishTime = null; + this.multiplayerStarted = false; + this.timeState.ticks = 0; + + for (marble in this.marbles) { + restart(marble, true); + } + + showPreGame(); + + serverStartTicks = 0; + startTime = 1e8; + } + + public function partialRestart() { + this.finishTime = null; + this.multiplayerStarted = false; + this.timeState.ticks = 0; + + for (marble in this.marbles) { + restart(marble, true); + } + + startTime = this.timeState.timeSinceLoad + 3.5; + + if (Net.isHost) { + haxe.Timer.delay(() -> { + NetCommands.setStartTicks(this.timeState.ticks); + }, 500); + } + this.gameMode.onRestart(); + } + public function getWorldStateForClientJoin() { var packets = []; // First, gem spawn packet diff --git a/src/gui/MPEndGameGui.hx b/src/gui/MPEndGameGui.hx index 13389afa..94cf6122 100644 --- a/src/gui/MPEndGameGui.hx +++ b/src/gui/MPEndGameGui.hx @@ -1,5 +1,6 @@ package gui; +import net.NetCommands; import net.Net; import h3d.shader.AlphaChannel; import hxd.res.BitmapFont; @@ -109,8 +110,13 @@ class MPEndGameGui extends GuiImage { var restartBtn = new GuiButton(loadButtonImagesExt("data/ui/mp/end/restart")); restartBtn.position = new Vector(5, 7); restartBtn.extent = new Vector(49, 49); + restartBtn.pressedAction = (e) -> { + MarbleGame.canvas.popDialog(this); + MarbleGame.instance.paused = false; + NetCommands.completeRestartGame(); + } if (Net.isClient) { - lobbyBtn.disabled = true; + restartBtn.disabled = true; } sidebar.addChild(restartBtn); diff --git a/src/gui/MPExitGameDlg.hx b/src/gui/MPExitGameDlg.hx index 8e34c33e..9953937c 100644 --- a/src/gui/MPExitGameDlg.hx +++ b/src/gui/MPExitGameDlg.hx @@ -1,5 +1,6 @@ package gui; +import net.NetCommands; import h2d.filter.DropShadow; import net.Net; import src.MarbleGame; @@ -43,6 +44,11 @@ class MPExitGameDlg extends GuiControl { partialRestart.position = new Vector(133, 80); partialRestart.extent = new Vector(94, 45); partialRestart.vertSizing = Top; + partialRestart.pressedAction = (e) -> { + MarbleGame.instance.paused = false; + NetCommands.partialRestartGame(); + MarbleGame.canvas.popDialog(this); + } dialogImg.addChild(partialRestart); if (!Net.isHost) { partialRestart.disabled = true; @@ -93,6 +99,11 @@ class MPExitGameDlg extends GuiControl { completeRestart.position = new Vector(224, 80); completeRestart.extent = new Vector(104, 45); completeRestart.vertSizing = Top; + completeRestart.pressedAction = (e) -> { + MarbleGame.instance.paused = false; + NetCommands.completeRestartGame(); + MarbleGame.canvas.popDialog(this); + } dialogImg.addChild(completeRestart); if (!Net.isHost) { completeRestart.disabled = true; diff --git a/src/modes/HuntMode.hx b/src/modes/HuntMode.hx index ad0fcf6d..8eb356b4 100644 --- a/src/modes/HuntMode.hx +++ b/src/modes/HuntMode.hx @@ -114,6 +114,12 @@ class HuntMode extends NullMode { } } + public function freeSpawns() { + for (i in 0...playerSpawnPoints.length) { + spawnPointTaken[i] = false; + } + } + override function getRespawnTransform(marble:Marble) { var lastContactPos = marble.lastContactPosition; if (lastContactPos == null) { @@ -181,12 +187,17 @@ class HuntMode extends NullMode { } } } + for (i in 0...spawnPointTaken.length) { + spawnPointTaken[i] = false; + } } function setupGems() { hideExisting(); this.activeGems = []; this.activeGemSpawnGroup = []; + this.rng.setSeed(cast Math.random() * 10000); + this.rng2.setSeed(cast Math.random() * 10000); prepareGems(); spawnHuntGems(); } @@ -362,6 +373,7 @@ class HuntMode extends NullMode { if (level.finishTime != null) return; + AudioManager.playSound(ResourceLoader.getResource("data/sound/firewrks.wav", ResourceLoader.getAudio, @:privateAccess level.soundResources)); // AudioManager.playSound(ResourceLoader.getResource('data/sound/finish.wav', ResourceLoader.getAudio, @:privateAccess level.soundResources)); level.finishTime = level.timeState.clone(); level.marble.setMode(Finish); @@ -389,7 +401,7 @@ class HuntMode extends NullMode { } level.schedule(level.timeState.currentAttemptTime + 2, () -> { - MarbleGame.canvas.setContent(new MPEndGameGui()); + MarbleGame.canvas.pushDialog(new MPEndGameGui()); level.setCursorLock(false); return 0; }); diff --git a/src/net/NetCommands.hx b/src/net/NetCommands.hx index 4369d0fd..2967961d 100644 --- a/src/net/NetCommands.hx +++ b/src/net/NetCommands.hx @@ -1,5 +1,7 @@ package net; +import gui.MPExitGameDlg; +import gui.MPEndGameGui; import gui.MPPreGameDlg; import gui.MPPlayMissionGui; import net.ClientConnection.NetPlatform; @@ -308,21 +310,36 @@ class NetCommands { } } - @:rpc(server) public static function restartGame() { - var world = MarbleGame.instance.world; - if (Net.isHost) { - world.startTime = 1e8; - haxe.Timer.delay(() -> world.allClientsReady(), 1500); - } + @:rpc(server) public static function completeRestartGame() { if (Net.isClient) { var gui = MarbleGame.canvas.children[MarbleGame.canvas.children.length - 1]; - if (gui is EndGameGui) { - var egg = cast(gui, EndGameGui); + if (gui is MPEndGameGui || gui is MPExitGameDlg) { + MarbleGame.instance.paused = false; + MarbleGame.canvas.popDialog(gui); // egg.retryFunc(null); - world.restartMultiplayerState(); } } - world.multiplayerStarted = false; + var world = MarbleGame.instance.world; + world.completeRestart(); + if (Net.isClient) { + world.restartMultiplayerState(); + } + } + + @:rpc(server) public static function partialRestartGame() { + if (Net.isClient) { + var gui = MarbleGame.canvas.children[MarbleGame.canvas.children.length - 1]; + if (gui is MPEndGameGui || gui is MPExitGameDlg) { + MarbleGame.instance.paused = false; + MarbleGame.canvas.popDialog(gui); + // egg.retryFunc(null); + } + } + var world = MarbleGame.instance.world; + world.partialRestart(); + if (Net.isClient) { + world.restartMultiplayerState(); + } } @:rpc(server) public static function ping(sendTime:Float) { diff --git a/src/shaders/NoiseTileMaterial.hx b/src/shaders/NoiseTileMaterial.hx index 5c3bd433..e36cc006 100644 --- a/src/shaders/NoiseTileMaterial.hx +++ b/src/shaders/NoiseTileMaterial.hx @@ -10,7 +10,7 @@ class NoiseTileMaterial extends hxsl.Shader { @param var ambientLight:Vec3; @param var dirLight:Vec3; @param var dirLightDir:Vec3; - @param var secondaryMapUvFactor:Float; + @param var uvScaleFactor:Float; @global var camera:{ var position:Vec3; @var var dir:Vec3; @@ -40,7 +40,7 @@ class NoiseTileMaterial extends hxsl.Shader { return saturate(result); } function vertex() { - calculatedUV = input.uv; + calculatedUV = input.uv * uvScaleFactor; fragLightW = step(0, dot(dirLight, input.normal)); } function fragment() { @@ -77,7 +77,7 @@ class NoiseTileMaterial extends hxsl.Shader { var outCol = diffuse + noiseAdd; var n = transformedNormal; - var nf = unpackNormal(normalMap.get(calculatedUV * secondaryMapUvFactor)); + var nf = unpackNormal(normalMap.get(calculatedUV)); var tanX = transformedTangent.xyz.normalize(); var tanY = n.cross(tanX) * transformedTangent.w; transformedNormal = (nf.x * tanX + nf.y * tanY + nf.z * n).normalize(); @@ -116,6 +116,6 @@ class NoiseTileMaterial extends hxsl.Shader { this.ambientLight = ambientLight.clone(); this.dirLight = dirLight.clone(); this.dirLightDir = dirLightDir.clone(); - this.secondaryMapUvFactor = secondaryMapUvFactor; + this.uvScaleFactor = secondaryMapUvFactor; } }