From 7d3c373a400c61db7281e72033fec02b7df2fc1d Mon Sep 17 00:00:00 2001 From: RandomityGuy <31925790+RandomityGuy@users.noreply.github.com> Date: Sat, 26 Jun 2021 23:03:41 +0530 Subject: [PATCH] finally added proper highscore saving shit and save load shit --- .gitignore | 3 +- src/Main.hx | 2 + src/MarbleWorld.hx | 9 ++-- src/ResourceLoader.hx | 31 +++++++------- src/Settings.hx | 52 +++++++++++++++++++++++ src/Util.hx | 18 ++++++++ src/gui/EndGameGui.hx | 64 ++++++++++++++++++++++++++-- src/gui/EnterNameDlg.hx | 87 +++++++++++++++++++++++++++++++++++++++ src/gui/GuiTextInput.hx | 53 ++++++++++++++++++++++++ src/gui/PlayMissionGui.hx | 12 +++++- 10 files changed, 306 insertions(+), 25 deletions(-) create mode 100644 src/Settings.hx create mode 100644 src/gui/EnterNameDlg.hx create mode 100644 src/gui/GuiTextInput.hx diff --git a/.gitignore b/.gitignore index b6debea5..fb21d30f 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ data .vscode native *.exe -*.obj \ No newline at end of file +*.obj +settings.json \ No newline at end of file diff --git a/src/Main.hx b/src/Main.hx index b7f0f9e1..1a288777 100644 --- a/src/Main.hx +++ b/src/Main.hx @@ -1,5 +1,6 @@ package; +import src.Settings; import src.MarbleGame; import gui.MainMenuGui; import hxd.res.DefaultFont; @@ -14,6 +15,7 @@ class Main extends hxd.App { override function init() { super.init(); + Settings.load(); marbleGame = new MarbleGame(s2d, s3d); MarbleGame.canvas.setContent(new MainMenuGui()); // world = new MarbleWorld(s3d, s2d, mission); diff --git a/src/MarbleWorld.hx b/src/MarbleWorld.hx index d6f09f2a..ac98978f 100644 --- a/src/MarbleWorld.hx +++ b/src/MarbleWorld.hx @@ -628,8 +628,6 @@ class MarbleWorld extends Scheduler { public function updateTimer(dt:Float) { this.timeState.dt = dt; - this.timeState.currentAttemptTime += dt; - this.timeState.timeSinceLoad += dt; if (this.bonusTime != 0 && this.timeState.currentAttemptTime >= 3.5) { this.bonusTime -= dt; if (this.bonusTime < 0) { @@ -639,7 +637,12 @@ class MarbleWorld extends Scheduler { } else { if (this.timeState.currentAttemptTime >= 3.5) this.timeState.gameplayClock += dt; + else if (this.timeState.currentAttemptTime + dt >= 3.5) { + this.timeState.gameplayClock += (this.timeState.currentAttemptTime + dt) - 3.5; + } } + this.timeState.currentAttemptTime += dt; + this.timeState.timeSinceLoad += dt; if (finishTime != null) this.timeState.gameplayClock = finishTime.gameplayClock; playGui.formatTimer(this.timeState.gameplayClock); @@ -805,7 +808,7 @@ class MarbleWorld extends Scheduler { MarbleGame.canvas.popDialog(egg); this.setCursorLock(true); this.restart(); - }); + }, mission, finishTime); MarbleGame.canvas.pushDialog(egg); this.setCursorLock(false); return 0; diff --git a/src/ResourceLoader.hx b/src/ResourceLoader.hx index bbf50b82..ea5e58a2 100644 --- a/src/ResourceLoader.hx +++ b/src/ResourceLoader.hx @@ -21,20 +21,21 @@ class ResourceLoader { static var dtsResources:Map = new Map(); static var textureCache:Map = new Map(); static var imageCache:Map = new Map(); - static var threadPool:FixedThreadPool = new FixedThreadPool(4); + + // static var threadPool:FixedThreadPool = new FixedThreadPool(4); public static function loadInterior(path:String) { if (interiorResources.exists(path)) return interiorResources.get(path); else { var itr:Dif; - var lock = new Lock(); - threadPool.run(() -> { - itr = Dif.Load(path); - interiorResources.set(path, itr); - lock.release(); - }); - lock.wait(); + // var lock = new Lock(); + // threadPool.run(() -> { + itr = Dif.Load(path); + interiorResources.set(path, itr); + // lock.release(); + // }); + // lock.wait(); return itr; } } @@ -44,13 +45,13 @@ class ResourceLoader { return dtsResources.get(path); else { var dts = new DtsFile(); - var lock = new Lock(); - threadPool.run(() -> { - dts.read(path); - dtsResources.set(path, dts); - lock.release(); - }); - lock.wait(); + // var lock = new Lock(); + // threadPool.run(() -> { + dts.read(path); + dtsResources.set(path, dts); + // lock.release(); + // }); + // lock.wait(); return dts; } } diff --git a/src/Settings.hx b/src/Settings.hx new file mode 100644 index 00000000..54ced5b9 --- /dev/null +++ b/src/Settings.hx @@ -0,0 +1,52 @@ +package src; + +import haxe.DynamicAccess; +import sys.io.File; +import src.ResourceLoader; +import haxe.Json; + +typedef Score = { + var name:String; + var time:Float; +} + +class Settings { + public static var highScores:Map> = []; + + public static function saveScore(mapPath:String, score:Score) { + if (highScores.exists(mapPath)) { + var scoreList = highScores.get(mapPath); + scoreList.push(score); + scoreList.sort((a, b) -> a.time == b.time ? 0 : (a.time > b.time ? 1 : -1)); + } else { + highScores.set(mapPath, [score]); + } + save(); + } + + public static function getScores(mapPath:String) { + if (highScores.exists(mapPath)) { + return highScores.get(mapPath).copy(); + } else { + return []; + } + } + + public static function save() { + var outputData = { + highScores: highScores + }; + var json = Json.stringify(outputData); + File.saveContent("settings.json", json); + } + + public static function load() { + if (ResourceLoader.fileSystem.exists("settings.json")) { + var json = Json.parse(ResourceLoader.fileSystem.get("settings.json").getText()); + var highScoreData:DynamicAccess> = json.highScores; + for (key => value in highScoreData) { + highScores.set(key, value); + } + } + } +} diff --git a/src/Util.hx b/src/Util.hx index 7c655c2e..d7856280 100644 --- a/src/Util.hx +++ b/src/Util.hx @@ -157,4 +157,22 @@ class Util { } return false; } + + public static function formatTime(time:Float) { + var et = time * 1000; + var thousandth = Math.floor(et % 10); + var hundredth = Math.floor((et % 1000) / 10); + var totalSeconds = Math.floor(et / 1000); + var seconds = totalSeconds % 60; + var minutes = (totalSeconds - seconds) / 60; + + var secondsOne = seconds % 10; + var secondsTen = (seconds - secondsOne) / 10; + var minutesOne = minutes % 10; + var minutesTen = (minutes - minutesOne) / 10; + var hundredthOne = hundredth % 10; + var hundredthTen = (hundredth - hundredthOne) / 10; + + return '${minutesTen}${minutesOne}:${secondsTen}${secondsOne}.${hundredthTen}${hundredthOne}${thousandth}'; + } } diff --git a/src/gui/EndGameGui.hx b/src/gui/EndGameGui.hx index 496c60cf..c69ca008 100644 --- a/src/gui/EndGameGui.hx +++ b/src/gui/EndGameGui.hx @@ -1,17 +1,28 @@ package gui; +import src.MarbleGame; +import src.Settings.Score; +import src.Settings.Settings; +import src.Mission; import h2d.filter.DropShadow; import hxd.res.BitmapFont; import h3d.Vector; import src.ResourceLoader; +import src.TimeState; +import src.Util; class EndGameGui extends GuiControl { - public function new(continueFunc:GuiControl->Void, restartFunc:GuiControl->Void) { + var mission:Mission; + + var scoreSubmitted:Bool = false; + + public function new(continueFunc:GuiControl->Void, restartFunc:GuiControl->Void, mission:Mission, timeState:TimeState) { super(); this.horizSizing = Width; this.vertSizing = Height; this.position = new Vector(0, 0); this.extent = new Vector(640, 480); + this.mission = mission; function loadButtonImages(path:String) { var normal = ResourceLoader.getImage('${path}_n.png').toTile(); @@ -69,7 +80,7 @@ class EndGameGui extends GuiControl { var congrats = new GuiMLText(expo50, mlFontLoader); congrats.text.textColor = 0xffff00; - congrats.text.text = 'Final Time: 99:59.999'; + congrats.text.text = 'Final Time: ${Util.formatTime(timeState.gameplayClock)}'; congrats.text.filter = new DropShadow(1.414, 0.785, 0, 1, 0, 0.4, 1, true); congrats.position = new Vector(43, 17); congrats.extent = new Vector(408, 50); @@ -84,17 +95,31 @@ class EndGameGui extends GuiControl { finishMessage.extent = new Vector(200, 100); pg.addChild(finishMessage); + var scoreData:Array = Settings.getScores(mission.path); + while (scoreData.length < 3) { + scoreData.push({name: "Nardo Polo", time: 5999.999}); + } + var leftColumn = new GuiMLText(domcasual32, mlFontLoader); leftColumn.text.textColor = 0x000000; - leftColumn.text.text = 'Qualify Time:
Gold Time:
Elapsed Time:
Bonus Time:

Best Times:
1. Nardo Polo
2. Nardo Polo
3. Nardo Polo'; + leftColumn.text.text = 'Qualify Time:
Gold Time:
Elapsed Time:
Bonus Time:

Best Times:
'; + for (i in 0...3) { + leftColumn.text.text += '${i + 1}. ${scoreData[i].name}
'; + } leftColumn.text.filter = new DropShadow(1.414, 0.785, 0xffffff, 1, 0, 0.4, 1, true); leftColumn.position = new Vector(108, 103); leftColumn.extent = new Vector(208, 50); pg.addChild(leftColumn); + var elapsedTime = Math.max(timeState.currentAttemptTime - 5.5, 0); + var bonusTime = Math.max(0, elapsedTime - timeState.gameplayClock); + var rightColumn = new GuiMLText(domcasual32, mlFontLoader); rightColumn.text.textColor = 0x000000; - rightColumn.text.text = '99:59.999
99:59.999
99:59.999
99:59.999


99:59.999
99:59.999
99:59.999'; + rightColumn.text.text = '${Util.formatTime(mission.qualifyTime == Math.POSITIVE_INFINITY ? 5999.999 : mission.qualifyTime)}
${Util.formatTime(mission.goldTime)}
${Util.formatTime(elapsedTime)}
${Util.formatTime(bonusTime)}


'; + for (i in 0...3) { + rightColumn.text.text += '${Util.formatTime(scoreData[i].time)}
'; + } rightColumn.text.filter = new DropShadow(1.414, 0.785, 0xffffff, 1, 0, 0.4, 1, true); rightColumn.position = new Vector(274, 103); rightColumn.extent = new Vector(208, 50); @@ -104,5 +129,36 @@ class EndGameGui extends GuiControl { pg.addChild(restartButton); this.addChild(pg); + + var scoreTimes = scoreData.map(x -> x.time).concat([timeState.gameplayClock]); + scoreTimes.sort((a, b) -> a == b ? 0 : (a > b ? 1 : -1)); + + var idx = scoreTimes.indexOf(timeState.gameplayClock); + + if (idx <= 2) { + var end = new EnterNameDlg(idx, (name) -> { + if (scoreSubmitted) + return; + + var myScore = {name: name, time: timeState.gameplayClock}; + scoreData.push(myScore); + scoreData.sort((a, b) -> a.time == b.time ? 0 : (a.time > b.time ? 1 : -1)); + + leftColumn.text.text = 'Qualify Time:
Gold Time:
Elapsed Time:
Bonus Time:

Best Times:
'; + for (i in 0...3) { + leftColumn.text.text += '${i + 1}. ${scoreData[i].name}
'; + } + + rightColumn.text.text = '${Util.formatTime(mission.qualifyTime == Math.POSITIVE_INFINITY ? 5999.999 : mission.qualifyTime)}
${Util.formatTime(mission.goldTime)}
${Util.formatTime(elapsedTime)}
${Util.formatTime(bonusTime)}


'; + for (i in 0...3) { + rightColumn.text.text += '${Util.formatTime(scoreData[i].time)}
'; + } + + Settings.saveScore(mission.path, myScore); + + scoreSubmitted = true; + }); + this.addChild(end); + } } } diff --git a/src/gui/EnterNameDlg.hx b/src/gui/EnterNameDlg.hx new file mode 100644 index 00000000..81d4f762 --- /dev/null +++ b/src/gui/EnterNameDlg.hx @@ -0,0 +1,87 @@ +package gui; + +import hxd.res.BitmapFont; +import h3d.Vector; +import src.ResourceLoader; +import src.MarbleGame; + +class EnterNameDlg extends GuiControl { + public function new(place:Int, okFunc:String->Void) { + super(); + this.position = new Vector(); + this.extent = new Vector(640, 480); + this.horizSizing = Width; + this.vertSizing = Height; + + function loadButtonImages(path:String) { + var normal = ResourceLoader.getImage('${path}_n.png').toTile(); + var hover = ResourceLoader.getImage('${path}_h.png').toTile(); + var pressed = ResourceLoader.getImage('${path}_d.png').toTile(); + return [normal, hover, pressed]; + } + + var arial14fontdata = ResourceLoader.loader.load("data/font/Arial14.fnt"); + var arial14 = new BitmapFont(arial14fontdata.entry); + @:privateAccess arial14.loader = ResourceLoader.loader; + + var domcasual32fontdata = ResourceLoader.loader.load("data/font/DomCasual32px.fnt"); + var domcasual32 = new BitmapFont(domcasual32fontdata.entry); + @:privateAccess domcasual32.loader = ResourceLoader.loader; + + var expo50fontdata = ResourceLoader.loader.load("data/font/Expo50.fnt"); + var expo50 = new BitmapFont(expo50fontdata.entry); + @:privateAccess expo50.loader = ResourceLoader.loader; + + var expo32fontdata = ResourceLoader.loader.load("data/font/Expo32.fnt"); + var expo32 = new BitmapFont(expo32fontdata.entry); + @:privateAccess expo32.loader = ResourceLoader.loader; + + function mlFontLoader(text:String) { + switch (text) { + case "DomCasual32": + return domcasual32.toFont(); + case "Arial14": + return arial14.toFont(); + case "Expo50": + return expo50.toFont(); + default: + return null; + } + } + + var dlg = new GuiImage(ResourceLoader.getImage("data/ui/common/dialog.png").toTile()); + dlg.horizSizing = Center; + dlg.vertSizing = Center; + dlg.position = new Vector(112, 111); + dlg.extent = new Vector(416, 257); + this.addChild(dlg); + + var enterNameEdit = new GuiTextInput(domcasual32); + enterNameEdit.position = new Vector(87, 136); + enterNameEdit.extent = new Vector(255, 36); + + var okbutton = new GuiButton(loadButtonImages("data/ui/common/ok")); + okbutton.position = new Vector(163, 182); + okbutton.extent = new Vector(78, 59); + okbutton.pressedAction = (sender) -> { + MarbleGame.canvas.popDialog(this); + okFunc(enterNameEdit.text.text); + } + dlg.addChild(okbutton); + + var wnd = new GuiImage(ResourceLoader.getImage("data/ui/common/window.png").toTile()); + wnd.position = new Vector(58, 124); + wnd.extent = new Vector(295, 55); + dlg.addChild(wnd); + + var enterNameText = new GuiMLText(domcasual32, mlFontLoader); + enterNameText.text.textColor = 0; + enterNameText.position = new Vector(41, 30); + enterNameText.extent = new Vector(345, 14); + // enterNameText.justify = Center; + enterNameText.text.text = '

Congratulations
You got the${["", " 2nd", " 3rd"][place]} best time!

'; + dlg.addChild(enterNameText); + + dlg.addChild(enterNameEdit); + } +} diff --git a/src/gui/GuiTextInput.hx b/src/gui/GuiTextInput.hx new file mode 100644 index 00000000..7ff4ce1b --- /dev/null +++ b/src/gui/GuiTextInput.hx @@ -0,0 +1,53 @@ +package gui; + +import h2d.TextInput; +import h2d.Scene; +import hxd.res.BitmapFont; +import gui.GuiText.Justification; +import h2d.Text; +import src.ResourceLoader; +import src.MarbleGame; + +class GuiTextInput extends GuiControl { + var text:TextInput; + var justify:Justification = Left; + + public function new(font:BitmapFont) { + super(); + this.text = new TextInput(font.toFont()); + this.text.textColor = 0; + } + + public override function render(scene2d:Scene) { + var renderRect = this.getRenderRectangle(); + if (justify == Left) { + text.setPosition(renderRect.position.x, renderRect.position.y); + text.textAlign = Left; + } + if (justify == Right) { + text.setPosition(renderRect.position.x + renderRect.extent.x, renderRect.position.y); + text.textAlign = Right; + } + if (justify == Center) { + text.setPosition(renderRect.position.x + renderRect.extent.x / 2, renderRect.position.y); + text.textAlign = Center; + } + if (scene2d.contains(text)) + scene2d.removeChild(text); + scene2d.addChild(text); + this.text.inputWidth = cast renderRect.extent.x; + super.render(scene2d); + } + + public override function dispose() { + super.dispose(); + this.text.remove(); + } + + public override function onRemove() { + super.onRemove(); + if (MarbleGame.canvas.scene2d.contains(text)) { + MarbleGame.canvas.scene2d.removeChild(text); // Refresh "layer" + } + } +} diff --git a/src/gui/PlayMissionGui.hx b/src/gui/PlayMissionGui.hx index 73b10b90..5928a992 100644 --- a/src/gui/PlayMissionGui.hx +++ b/src/gui/PlayMissionGui.hx @@ -1,5 +1,7 @@ package gui; +import src.Settings.Score; +import src.Settings.Settings; import haxe.io.Path; import h2d.Scene; import h2d.Text; @@ -297,11 +299,17 @@ class PlayMissionGui extends GuiImage { pmNext.disabled = false; var currentMission = currentList[currentSelection]; + + var scoreData:Array = Settings.getScores(currentMission.path); + while (scoreData.length < 3) { + scoreData.push({name: "Nardo Polo", time: 5999.999}); + } + var descText = '${currentMission.title}

' + splitTextWithPadding(pmDescription.text, Util.unescape(currentMission.description)); descText += '

Best Times:
'; for (i in 0...3) { - descText += '
ÂÂ${i + 1}. Nardo Polo'; + descText += '
ÂÂ${i + 1}. ${scoreData[i].name}'; } pmDescription.text.text = descText; @@ -309,7 +317,7 @@ class PlayMissionGui extends GuiImage { + '${splitTextWithPadding(pmDescriptionOther.text, Util.unescape(currentMission.description))}'; descText2 += '


'; for (i in 0...3) { - descText2 += '
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ00:00.000'; + descText2 += '
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ${Util.formatTime(scoreData[i].time)}'; } pmDescriptionOther.text.text = descText2;