From 7837be38e9c9a2ccbe48016277825dab67c16824 Mon Sep 17 00:00:00 2001 From: RandomityGuy <31925790+RandomityGuy@users.noreply.github.com> Date: Fri, 21 Jun 2024 22:42:30 +0530 Subject: [PATCH] end game initial --- src/MarbleWorld.hx | 13 +- src/gui/MPEndGameGui.hx | 277 ++++++++++++++++++++++++++++++++++++ src/gui/PlayGui.hx | 23 ++- src/modes/HuntMode.hx | 57 +++++++- src/net/ClientConnection.hx | 8 +- src/net/Net.hx | 8 +- src/net/NetCommands.hx | 4 +- src/net/NetPacket.hx | 15 +- 8 files changed, 389 insertions(+), 16 deletions(-) create mode 100644 src/gui/MPEndGameGui.hx diff --git a/src/MarbleWorld.hx b/src/MarbleWorld.hx index 70da6173..bb593d9a 100644 --- a/src/MarbleWorld.hx +++ b/src/MarbleWorld.hx @@ -500,7 +500,7 @@ class MarbleWorld extends Scheduler { if (client == null) { marblefiles.push(StringTools.replace(Settings.optionsSettings.marbleModel, "data/", "")); } else { - var marbleDts = MarbleSelectGui.marbleData[0][client.getMarbleId()].dts; // FIXME + var marbleDts = MarbleSelectGui.marbleData[client.getMarbleCatId()][client.getMarbleId()].dts; // FIXME marblefiles.push(StringTools.replace(marbleDts, "data/", "")); } @@ -1581,9 +1581,9 @@ class MarbleWorld extends Scheduler { return; } - if (Key.isPressed(Key.T)) { - rollback(0.4); - } + // if (Key.isPressed(Key.T)) { + // rollback(0.4); + // } var realDt = dt; @@ -2021,10 +2021,9 @@ class MarbleWorld extends Scheduler { AudioManager.playSound(ResourceLoader.getResource("data/sound/alarm_timeout.wav", ResourceLoader.getAudio, this.soundResources)); } } - - if (finishTime != null) - this.timeState.gameplayClock = finishTime.gameplayClock; } + if (finishTime != null) + this.timeState.gameplayClock = finishTime.gameplayClock; playGui.formatTimer(this.timeState.gameplayClock, determineClockColor(this.timeState.gameplayClock)); if (!this.isWatching && this.isRecording) diff --git a/src/gui/MPEndGameGui.hx b/src/gui/MPEndGameGui.hx new file mode 100644 index 00000000..13389afa --- /dev/null +++ b/src/gui/MPEndGameGui.hx @@ -0,0 +1,277 @@ +package gui; + +import net.Net; +import h3d.shader.AlphaChannel; +import hxd.res.BitmapFont; +import src.MarbleGame; +import src.ResourceLoader; +import h3d.Vector; +import src.Settings; +import src.DtsObject; + +class MPEndGameGui extends GuiImage { + public function new() { + var img = ResourceLoader.getImage('data/ui/exit/black.png'); + super(img.resource.toTile()); + this.horizSizing = Width; + this.vertSizing = Height; + this.position = new Vector(0, 0); + this.extent = new Vector(640, 480); + + 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 domcasual36 = domcasual24b.toSdfFont(cast 32 * 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); + + var expo50fontdata = ResourceLoader.getFileEntry("data/font/EXPON.fnt"); + var expo50b = new BitmapFont(expo50fontdata.entry); + @:privateAccess expo50b.loader = ResourceLoader.loader; + var expo50 = expo50b.toSdfFont(cast 35 * 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; + } + } + + 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 sidebar = new GuiImage(ResourceLoader.getResource("data/ui/mp/end/window.png", ResourceLoader.getImage, this.imageResources).toTile()); + sidebar.position = new Vector(587, 141); + sidebar.extent = new Vector(53, 198); + sidebar.horizSizing = Left; + sidebar.vertSizing = Center; + this.addChild(sidebar); + + var lobbyBtn = new GuiButton(loadButtonImagesExt("data/ui/mp/end/lobby")); + lobbyBtn.position = new Vector(5, 53); + lobbyBtn.extent = new Vector(49, 49); + lobbyBtn.vertSizing = Top; + lobbyBtn.pressedAction = (e) -> { + MarbleGame.instance.quitMission(); + } + if (Net.isClient) { + lobbyBtn.disabled = true; + } + sidebar.addChild(lobbyBtn); + + var restartBtn = new GuiButton(loadButtonImagesExt("data/ui/mp/end/restart")); + restartBtn.position = new Vector(5, 7); + restartBtn.extent = new Vector(49, 49); + if (Net.isClient) { + lobbyBtn.disabled = true; + } + sidebar.addChild(restartBtn); + + var exitBtn = new GuiButton(loadButtonImagesExt("data/ui/mp/end/exit")); + exitBtn.position = new Vector(5, 99); + exitBtn.extent = new Vector(49, 49); + exitBtn.vertSizing = Top; + exitBtn.horizSizing = Left; + sidebar.addChild(exitBtn); + + var middleCtrl = new GuiControl(); + middleCtrl.horizSizing = Center; + middleCtrl.vertSizing = Height; + middleCtrl.position = new Vector(-80, 0); + middleCtrl.extent = new Vector(800, 480); + this.addChild(middleCtrl); + + var headerML = new GuiText(domcasual36); + headerML.position = new Vector(25, 83); + headerML.extent = new Vector(750, 14); + headerML.horizSizing = Width; + headerML.text.textColor = 0xFFFFFF; + headerML.text.text = " Name Score Marble"; + middleCtrl.addChild(headerML); + + var scores = @:privateAccess MarbleGame.instance.world.playGui.playerList; + var ourRank = scores.indexOf(scores.filter(x -> x.us == true)[0]) + 1; + var rankSuffix = ourRank == 1 ? "st" : (ourRank == 2 ? "nd" : (ourRank == 3 ? "rd" : "th")); + + var col0 = 0xCFB52B; + var col1 = 0xCDCDCD; + var col2 = 0xD19275; + var col3 = 0xFFEE99; + + var rankColor = ourRank == 1 ? col0 : (ourRank == 2 ? col1 : (ourRank == 3 ? col2 : col3)); + + var titleML = new GuiText(expo50); + titleML.position = new Vector(25, 6); + titleML.extent = new Vector(750, 14); + titleML.justify = Center; + titleML.horizSizing = Width; + titleML.text.textColor = rankColor; + titleML.text.dropShadow = { + dx: 1, + dy: 1, + alpha: 0.5, + color: 0 + }; + titleML.text.text = 'You have won ' + ourRank + rankSuffix + ' place!'; + middleCtrl.addChild(titleML); + + var redGem = buildObjectShow("data/shapes/items/gem.dts", new Vector(365, 65), new Vector(64, 64), 2.5, 0, ["base.gem" => "red.gem"]); + middleCtrl.addChild(redGem); + var yellowGem = buildObjectShow("data/shapes/items/gem.dts", new Vector(417, 65), new Vector(64, 64), 2.5, 0, ["base.gem" => "yellow.gem"]); + middleCtrl.addChild(yellowGem); + var blueGem = buildObjectShow("data/shapes/items/gem.dts", new Vector(469, 65), new Vector(64, 64), 2.5, 0, ["base.gem" => "blue.gem"]); + middleCtrl.addChild(blueGem); + + var playerContainer = new GuiControl(); + playerContainer.horizSizing = Center; + playerContainer.vertSizing = Height; + playerContainer.position = new Vector(25, 125); + playerContainer.extent = new Vector(750, 275); + middleCtrl.addChild(playerContainer); + + var idx = 0; + + function addPlayer(rank:Int, playerName:String, score:Int, r:Int, y:Int, b:Int, marbleCat:Int, marbleSel:Int) { + var container = new GuiControl(); + container.position = new Vector(0, 44 * idx); + container.extent = new Vector(750, 44); + + var playerNameT = new GuiText(domcasual36); + playerNameT.text.textColor = 0xFFFFFF; + playerNameT.text.text = '${rank}. ${playerName}'; + playerNameT.position = new Vector(0, 3); + playerNameT.extent = new Vector(300, 14); + container.addChild(playerNameT); + + var playerScore = new GuiText(domcasual36); + playerScore.text.textColor = 0xFFFFFF; + playerScore.text.text = '${score}'; + playerScore.position = new Vector(287, 3); + playerScore.extent = new Vector(310, 14); + container.addChild(playerScore); + + var playerR = new GuiText(domcasual36); + playerR.text.textColor = 0xFF0000; + playerR.text.text = '${r}'; + playerR.justify = Center; + playerR.position = new Vector(348, 3); + playerR.extent = new Vector(52, 14); + container.addChild(playerR); + + var playerY = new GuiText(domcasual36); + playerY.text.textColor = 0xFFFF00; + playerY.text.text = '${y}'; + playerY.justify = Center; + playerY.position = new Vector(400, 3); + playerY.extent = new Vector(52, 14); + container.addChild(playerY); + + var playerB = new GuiText(domcasual36); + playerB.text.textColor = 0x0000FF; + playerB.text.text = '${b}'; + playerB.justify = Center; + playerB.position = new Vector(452, 3); + playerB.extent = new Vector(52, 14); + container.addChild(playerB); + + var marble = buildObjectShow(MarbleSelectGui.marbleData[marbleCat][marbleSel].dts, new Vector(524, -10), new Vector(64, 64), 2.4, 0, [ + "base.marble" => MarbleSelectGui.marbleData[marbleCat][marbleSel].skin + ".marble" + ]); + + container.addChild(marble); + + playerContainer.addChild(container); + + idx += 1; + } + + var r = 1; + for (player in scores) { + var cat = Settings.optionsSettings.marbleCategoryIndex; + var marb = Settings.optionsSettings.marbleIndex; + if (!player.us) { + var c = Net.clientIdMap[player.id]; + cat = c.marbleCatId; + marb = c.marbleId; + } + + addPlayer(r, player.name, player.score, player.r, player.y, player.b, cat, marb); + r += 1; + } + } + + 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/PlayGui.hx b/src/gui/PlayGui.hx index 6d4be8ff..5c793145 100644 --- a/src/gui/PlayGui.hx +++ b/src/gui/PlayGui.hx @@ -48,6 +48,9 @@ class PlayerInfo { var name:String; var us:Bool; var score:Int; + var r:Int; + var y:Int; + var b:Int; } class PlayGui { @@ -604,7 +607,10 @@ class PlayGui { id: id, name: name, us: us, - score: 0 + score: 0, + r: 0, + y: 0, + b: 0 }); redrawPlayerList(); } @@ -621,8 +627,18 @@ class PlayGui { public function incrementPlayerScore(id:Int, score:Int) { var f = playerList.filter(x -> x.id == id); - if (f.length != 0) + if (f.length != 0) { f[0].score += score; + if (score == 1) { + f[0].r += 1; + } + if (score == 2) { + f[0].y += 1; + } + if (score == 5) { + f[0].b += 1; + } + } if (id == Net.clientId) { if (Net.isClient) @@ -636,6 +652,9 @@ class PlayGui { public function updatePlayerScores(scoreboardPacket:ScoreboardPacket) { for (player in playerList) { player.score = scoreboardPacket.scoreBoard.exists(player.id) ? scoreboardPacket.scoreBoard.get(player.id) : 0; + player.r = scoreboardPacket.rBoard.exists(player.id) ? scoreboardPacket.rBoard.get(player.id) : 0; + player.y = scoreboardPacket.yBoard.exists(player.id) ? scoreboardPacket.yBoard.get(player.id) : 0; + player.b = scoreboardPacket.bBoard.exists(player.id) ? scoreboardPacket.bBoard.get(player.id) : 0; } redrawPlayerList(); } diff --git a/src/modes/HuntMode.hx b/src/modes/HuntMode.hx index e2ee26ec..ad0fcf6d 100644 --- a/src/modes/HuntMode.hx +++ b/src/modes/HuntMode.hx @@ -1,5 +1,7 @@ package modes; +import gui.MPEndGameGui; +import net.NetCommands; import net.BitStream.OutputBitStream; import net.NetPacket.GemPickupPacket; import net.NetPacket.GemSpawnPacket; @@ -21,6 +23,7 @@ import src.Marble; import src.AudioManager; import src.ResourceLoader; import net.Net; +import src.MarbleGame; @:structInit @:publicFields @@ -94,6 +97,7 @@ class HuntMode extends NullMode { 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; @@ -113,7 +117,21 @@ class HuntMode extends NullMode { override function getRespawnTransform(marble:Marble) { var lastContactPos = marble.lastContactPosition; if (lastContactPos == null) { - return getSpawnTransform(); + var idx = Math.floor(rng2.randRange(0, playerSpawnPoints.length - 1)); + 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 + } } // Pick closest spawn point var closestSpawn:MissionElementTrigger = null; @@ -340,6 +358,43 @@ class HuntMode extends NullMode { prepareGems(); } + override function onTimeExpire() { + if (level.finishTime != null) + return; + + // AudioManager.playSound(ResourceLoader.getResource('data/sound/finish.wav', ResourceLoader.getAudio, @:privateAccess level.soundResources)); + level.finishTime = level.timeState.clone(); + level.marble.setMode(Finish); + level.marble.camera.finish = true; + level.finishYaw = level.marble.camera.CameraYaw; + level.finishPitch = level.marble.camera.CameraPitch; + // if (level.isMultiplayer) { + // @:privateAccess level.playGui.doMPEndGameMessage(); + // } else { + // level.displayAlert("Congratulations! You've finished!"); + // } + level.cancel(@:privateAccess level.oobSchedule); + level.cancel(@:privateAccess level.marble.oobSchedule); + for (marble in level.marbles) { + marble.setMode(Finish); + level.cancel(@:privateAccess marble.oobSchedule); + } + if (Net.isHost) + NetCommands.timerRanOut(); + + // Stop the ongoing sounds + if (@:privateAccess level.timeTravelSound != null) { + @:privateAccess level.timeTravelSound.stop(); + @:privateAccess level.timeTravelSound = null; + } + + level.schedule(level.timeState.currentAttemptTime + 2, () -> { + MarbleGame.canvas.setContent(new MPEndGameGui()); + level.setCursorLock(false); + return 0; + }); + } + override function onGemPickup(marble:Marble, gem:Gem) { if ((@:privateAccess !marble.isNetUpdate && Net.isHost) || !Net.isMP) { if (marble == level.marble) diff --git a/src/net/ClientConnection.hx b/src/net/ClientConnection.hx index 2c5efacc..e89d3485 100644 --- a/src/net/ClientConnection.hx +++ b/src/net/ClientConnection.hx @@ -76,6 +76,7 @@ abstract class GameConnection { var lobbyReady:Bool; var platform:NetPlatform; var marbleId:Int; + var marbleCatId:Int; function new(id:Int) { this.id = id; @@ -127,11 +128,16 @@ abstract class GameConnection { name = value; } - public inline function setMarbleId(value:Int) { + public inline function setMarbleId(value:Int, category:Int) { marbleId = value; + marbleCatId = category; } public inline function getMarbleId() { return marbleId; } + + public inline function getMarbleCatId() { + return marbleCatId; + } } diff --git a/src/net/Net.hx b/src/net/Net.hx index f1a6718f..cea059e3 100644 --- a/src/net/Net.hx +++ b/src/net/Net.hx @@ -624,6 +624,7 @@ class Net { b.writeByte(v.lobbyReady ? 1 : 0); b.writeByte(v.platform); b.writeByte(v.marbleId); + b.writeByte(v.marbleCatId); var name = v.getName(); b.writeByte(name.length); for (i in 0...name.length) { @@ -635,6 +636,7 @@ class Net { b.writeByte(Net.lobbyHostReady ? 1 : 0); b.writeByte(getPlatform()); b.writeByte(Settings.optionsSettings.marbleIndex); + b.writeByte(Settings.optionsSettings.marbleCategoryIndex); var name = Settings.highscoreName; b.writeByte(name.length); for (i in 0...name.length) { @@ -657,7 +659,8 @@ class Net { case ClientIdAssign: clientId = input.readByte(); // 8 bit client id, hopefully we don't exceed this Console.log('Client ID set to ${clientId}'); - NetCommands.setPlayerData(clientId, Settings.highscoreName, Settings.optionsSettings.marbleIndex); // Send our player name to the server + NetCommands.setPlayerData(clientId, Settings.highscoreName, Settings.optionsSettings.marbleIndex, + Settings.optionsSettings.marbleCategoryIndex); // Send our player name to the server NetCommands.transmitPlatform(clientId, getPlatform()); // send our platform too case Ping: @@ -744,6 +747,7 @@ class Net { var cready = input.readByte() == 1; var platform = input.readByte(); var marble = input.readByte(); + var marbleCat = input.readByte(); if (id != 0 && id != Net.clientId && !clientIdMap.exists(id)) { Console.log('Adding ghost connection ${id}'); addGhost(id); @@ -756,7 +760,7 @@ class Net { } if (clientIdMap.exists(id)) { clientIdMap[id].setName(name); - clientIdMap[id].setMarbleId(marble); + clientIdMap[id].setMarbleId(marble, marbleCat); clientIdMap[id].lobbyReady = cready; clientIdMap[id].platform = platform; } diff --git a/src/net/NetCommands.hx b/src/net/NetCommands.hx index d7f6c4b5..4369d0fd 100644 --- a/src/net/NetCommands.hx +++ b/src/net/NetCommands.hx @@ -266,10 +266,10 @@ class NetCommands { } } - @:rpc(client) public static function setPlayerData(clientId:Int, name:String, marble:Int) { + @:rpc(client) public static function setPlayerData(clientId:Int, name:String, marble:Int, marbleCat:Int) { if (Net.isHost) { Net.clientIdMap[clientId].setName(name); - Net.clientIdMap[clientId].setMarbleId(marble); + Net.clientIdMap[clientId].setMarbleId(marble, marbleCat); if (MarbleGame.canvas.content is MPPlayMissionGui) { cast(MarbleGame.canvas.content, MPPlayMissionGui).updateLobbyNames(); } diff --git a/src/net/NetPacket.hx b/src/net/NetPacket.hx index a2c4c088..b2279de1 100644 --- a/src/net/NetPacket.hx +++ b/src/net/NetPacket.hx @@ -258,15 +258,25 @@ class GemPickupPacket implements NetPacket { @:publicFields class ScoreboardPacket implements NetPacket { var scoreBoard:Map; + var rBoard:Map; + var yBoard:Map; + var bBoard:Map; public function new() { scoreBoard = new Map(); + rBoard = new Map(); + yBoard = new Map(); + bBoard = new Map(); } public inline function deserialize(b:InputBitStream) { var count = b.readInt(4); for (i in 0...count) { - scoreBoard[b.readInt(6)] = b.readInt(10); + var id = b.readInt(6); + scoreBoard[id] = b.readInt(10); + rBoard[id] = b.readInt(10); + yBoard[id] = b.readInt(10); + bBoard[id] = b.readInt(10); } } @@ -278,6 +288,9 @@ class ScoreboardPacket implements NetPacket { for (key => v in scoreBoard) { b.writeInt(key, 6); b.writeInt(v, 10); + b.writeInt(rBoard[key], 10); + b.writeInt(yBoard[key], 10); + b.writeInt(bBoard[key], 10); } } }