mirror of
https://github.com/RandomityGuy/MBHaxe.git
synced 2025-12-23 16:32:49 +00:00
the long awaited marbleland customs support, oh and you can now play MP customs in SP as well
This commit is contained in:
parent
d2daa00181
commit
ff109d5c36
18 changed files with 610 additions and 114 deletions
|
|
@ -125,6 +125,10 @@ class DifBuilder {
|
|||
friction: 4.5,
|
||||
restitution: 0.5
|
||||
},
|
||||
"friction_ultrahigh" => {
|
||||
friction: 4.5,
|
||||
restitution: 0.5
|
||||
},
|
||||
"friction_ramp_yellow" => {
|
||||
friction: 2.0,
|
||||
restitution: 1.0
|
||||
|
|
@ -341,23 +345,38 @@ class DifBuilder {
|
|||
'tile_beginner_shadow' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_beginner.png', '_shadow', 40, new Vector(0.2, 0.2, 0.2, 0.2)),
|
||||
'tile_beginner_red' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_beginner.png', '_red', 40, new Vector(1, 1, 1, 1)),
|
||||
'tile_beginner_red_shadow' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_beginner.png', '_red_shadow', 40, new Vector(0.2, 0.2, 0.2, 0.2)),
|
||||
'tile_beginner_light' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_beginner.png', '_red', 40, new Vector(1, 1, 1, 1)), // MBP material
|
||||
'tile_beginner_blue' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_beginner.png', '_blue', 40, new Vector(1, 1, 1, 1)),
|
||||
'tile_beginner_blue_shadow' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_beginner.png', '_blue_shadow', 40, new Vector(0.2, 0.2, 0.2, 0.2)),
|
||||
'tile_beginner_dark' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_beginner.png', '_blue', 40, new Vector(1, 1, 1, 1)), // MBP material
|
||||
'tile_intermediate' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_intermediate.png', '', 40, new Vector(1, 1, 1, 1)),
|
||||
'tile_intermediate_shadow' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_intermediate.png', '_shadow', 40, new Vector(0.2, 0.2, 0.2, 0.2)),
|
||||
'tile_intermediate_red' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_intermediate.png', '_red', 40, new Vector(1, 1, 1, 1)),
|
||||
'tile_intermediate_red_shadow' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_intermediate.png', '_red_shadow', 40,
|
||||
new Vector(0.2, 0.2, 0.2, 0.2)),
|
||||
'tile_intermediate_dark' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_intermediate.png', '_red', 40,
|
||||
new Vector(1, 1, 1, 1)), // MBP material
|
||||
'tile_intermediate_green' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_intermediate.png', '_green', 40, new Vector(1, 1, 1, 1)),
|
||||
'tile_intermediate_green_shadow' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_intermediate.png', '_green_shadow', 40,
|
||||
new Vector(0.2, 0.2, 0.2, 0.2)),
|
||||
'tile_intermediate_light' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_intermediate.png', '_green', 40,
|
||||
new Vector(1, 1, 1, 1)), // MBP material
|
||||
'tile_advanced' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_advanced.png', '', 40, new Vector(1, 1, 1, 1)),
|
||||
'tile_advanced_shadow' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_advanced.png', '_shadow', 40, new Vector(0.2, 0.2, 0.2, 0.2)),
|
||||
'tile_advanced_blue' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_advanced.png', '_blue', 40, new Vector(1, 1, 1, 1)),
|
||||
'tile_advanced_blue_shadow' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_advanced.png', '_blue_shadow', 40, new Vector(0.2, 0.2, 0.2, 0.2)),
|
||||
'tile_advanced_dark' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_advanced.png', '_blue', 40, new Vector(1, 1, 1, 1)), // MBP material
|
||||
'tile_advanced_green' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_advanced.png', '_green', 40, new Vector(1, 1, 1, 1)),
|
||||
'tile_advanced_green_shadow' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_advanced.png', '_green_shadow', 40,
|
||||
new Vector(0.2, 0.2, 0.2, 0.2)),
|
||||
'tile_advanced_light' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_advanced.png', '_green', 40, new Vector(1, 1, 1, 1)), // MBP Material
|
||||
'tile_blue' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_intermediate.png', '_red', 40, new Vector(1, 1, 1, 1)), // MBP material
|
||||
'tile_bonus_blue' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_intermediate.png', '_red', 40, new Vector(1, 1, 1, 1)), // MBP material
|
||||
'tile_bonus_shadow' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_intermediate.png', '_red', 40, new Vector(1, 1, 1, 1)), // MBP material
|
||||
'tile_bonus' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_advanced.png', '_green', 40, new Vector(1, 1, 1, 1)), // MBP Material
|
||||
'tile_bonus_yellow' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_advanced.png', '_green', 40, new Vector(1, 1, 1, 1)), // MBP Material
|
||||
'tile_bonus_red' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_advanced.png', '_blue', 40, new Vector(1, 1, 1, 1)), // MBP material
|
||||
'tile_expert' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_advanced.png', '_blue', 40, new Vector(1, 1, 1, 1)), // MBP material
|
||||
'tile_underside' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_underside.png', '', 40, new Vector(1, 1, 1, 1)),
|
||||
// 4x4 Variant
|
||||
'tile_beginner_4x4' => (onFinish) -> createNoiseTileMaterial(onFinish, 'tile_beginner.png', '', 40, new Vector(1, 1, 1, 1), 4),
|
||||
|
|
@ -400,9 +419,13 @@ class DifBuilder {
|
|||
'data/textures/friction_low.normal.png', 128, new Vector(0.3, 0.3, 0.35, 1)),
|
||||
'friction_high' => (onFinish) -> createDefaultMaterial(onFinish, 'data/textures/friction_high.png', 'data/textures/friction_high.normal.png', 10,
|
||||
new Vector(0.3, 0.3, 0.35, 1)),
|
||||
'friction_ultrahigh' => (onFinish) -> createDefaultMaterial(onFinish, 'data/textures/friction_high.png', 'data/textures/friction_high.normal.png', 10,
|
||||
new Vector(0.3, 0.3, 0.35, 1)),
|
||||
'friction_high_shadow' => (onFinish) -> createDefaultMaterial(onFinish, 'data/textures/friction_high_shadow.png',
|
||||
'data/textures/friction_high.normal.png', 10, new Vector(0.15, 0.15, 0.16, 1.0)),
|
||||
'friction_bouncy' => (onFinish) -> createDefaultNormalMaterial(onFinish, 'data/textures/friction_bouncy.png', 8, new Vector(0.4, 0.4, 0.2, 1)),
|
||||
'tile_bouncy' => (onFinish) -> createDefaultNormalMaterial(onFinish, 'data/textures/friction_bouncy.png', 8, new Vector(0.4, 0.4, 0.2, 1)),
|
||||
'tile_bouncy2' => (onFinish) -> createDefaultNormalMaterial(onFinish, 'data/textures/friction_bouncy.png', 8, new Vector(0.4, 0.4, 0.2, 1)),
|
||||
'stripe_caution' => (onFinish) -> createDefaultNormalMaterial(onFinish, 'data/textures/stripe_caution.png', 12, new Vector(0.8, 0.8, 0.6, 1)),
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ class Leaderboards {
|
|||
}
|
||||
|
||||
public static function submitScore(mission:String, score:Float, rewindUsed:Bool, needsReplayCb:(Bool, Int) -> Void) {
|
||||
if (!StringTools.startsWith(mission, "data/"))
|
||||
if (!StringTools.startsWith(mission, "data/") && !StringTools.startsWith(mission, "custom/"))
|
||||
mission = "data/" + mission;
|
||||
Http.post('${host}/api/submit', Json.stringify({
|
||||
mission: mission,
|
||||
|
|
@ -58,7 +58,7 @@ class Leaderboards {
|
|||
}
|
||||
|
||||
public static function getScores(mission:String, kind:LeaderboardsKind, cb:Array<LBScore>->Void) {
|
||||
if (!StringTools.startsWith(mission, "data/"))
|
||||
if (!StringTools.startsWith(mission, "data/") && !StringTools.startsWith(mission, "custom/"))
|
||||
mission = "data/" + mission;
|
||||
return Http.get('${host}/api/scores?mission=${StringTools.urlEncode(mission)}&game=${game}&view=${kind}&count=10', (b) -> {
|
||||
var s = b.toString();
|
||||
|
|
@ -90,7 +90,7 @@ class Leaderboards {
|
|||
}
|
||||
|
||||
public static function watchTopReplay(mission:String, kind:LeaderboardsKind, cb:haxe.io.Bytes->Void) {
|
||||
if (!StringTools.startsWith(mission, "data/"))
|
||||
if (!StringTools.startsWith(mission, "data/") && !StringTools.startsWith(mission, "custom/"))
|
||||
mission = "data/" + mission;
|
||||
return Http.get('${host}/api/replay?mission=${StringTools.urlEncode(mission)}&game=${game}&view=${kind}', (b) -> {
|
||||
cb(b);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
package src;
|
||||
|
||||
import src.Mission;
|
||||
import src.MissionList;
|
||||
import gui.MessageBoxOkDlg;
|
||||
import haxe.zip.Reader;
|
||||
|
|
@ -7,12 +10,15 @@ import src.Http;
|
|||
import src.Console;
|
||||
import src.MarbleGame;
|
||||
import src.ResourceLoader;
|
||||
import src.Marbleland;
|
||||
import Main;
|
||||
|
||||
typedef MPCustomEntry = {
|
||||
artist:String,
|
||||
description:String,
|
||||
path:String,
|
||||
title:String
|
||||
title:String,
|
||||
id:Int,
|
||||
};
|
||||
|
||||
class MPCustoms {
|
||||
|
|
@ -31,6 +37,26 @@ class MPCustoms {
|
|||
var b1 = b.title.toLowerCase();
|
||||
return a1 < b1 ? -1 : (a1 > b1 ? 1 : 0);
|
||||
});
|
||||
|
||||
// Add this to marbleland customs too!
|
||||
for (mis in missionList) {
|
||||
var mission = new Mission();
|
||||
|
||||
mission.id = mis.id;
|
||||
mission.path = mis.path;
|
||||
mission.title = mis.title;
|
||||
mission.artist = mis.artist;
|
||||
mission.description = mis.description;
|
||||
mission.qualifyTime = Math.POSITIVE_INFINITY;
|
||||
mission.goldTime = 0;
|
||||
mission.game = 'ultra';
|
||||
mission.isClaMission = true;
|
||||
mission.customSource = "MPCustoms";
|
||||
|
||||
Marbleland.ultraMissions.push(mission);
|
||||
Marbleland.missions.set(mission.id, mission);
|
||||
}
|
||||
|
||||
Console.log('Loaded ${misList.length} custom missions.');
|
||||
_requestSent = false;
|
||||
}, (e) -> {
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import src.MissionList;
|
|||
import src.Analytics;
|
||||
import net.MasterServerClient;
|
||||
import src.Leaderboards;
|
||||
import src.MPCustoms;
|
||||
|
||||
class Main extends hxd.App {
|
||||
var marbleGame:MarbleGame;
|
||||
|
|
@ -130,7 +131,7 @@ class Main extends hxd.App {
|
|||
ResourceLoader.init(s2d, () -> {
|
||||
AudioManager.init();
|
||||
AudioManager.playShell();
|
||||
// Marbleland.init();
|
||||
Marbleland.init();
|
||||
marbleGame = new MarbleGame(s2d, s3d);
|
||||
MarbleGame.canvas.setContent(new PresentsGui());
|
||||
MissionList.buildMissionList(); // Yeah pls
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package src;
|
||||
|
||||
import gui.SPCustomsGui;
|
||||
import gui.GuiControl;
|
||||
import haxe.io.Path;
|
||||
import gui.MultiplayerGui;
|
||||
|
|
@ -42,7 +43,7 @@ class MarbleGame {
|
|||
static var canvas:Canvas;
|
||||
static var instance:MarbleGame;
|
||||
|
||||
static var currentVersion = "1.2.4";
|
||||
static var currentVersion = "1.2.5";
|
||||
|
||||
var world:MarbleWorld;
|
||||
var previewWorld:PreviewWorld;
|
||||
|
|
@ -365,12 +366,22 @@ class MarbleGame {
|
|||
canvas.setContent(lobby);
|
||||
}
|
||||
} else {
|
||||
var pmg = new LevelSelectGui(LevelSelectGui.currentDifficultyStatic);
|
||||
if (_exitingToMenu) {
|
||||
_exitingToMenu = false;
|
||||
if (!isNotCustom) {
|
||||
MarbleGame.instance.setPreviewMission('urban', () -> {});
|
||||
}
|
||||
canvas.setContent(new MainMenuGui());
|
||||
} else {
|
||||
if (isNotCustom) {
|
||||
var pmg = new LevelSelectGui(LevelSelectGui.currentDifficultyStatic);
|
||||
canvas.setContent(pmg);
|
||||
} else {
|
||||
// Load to the custom menu
|
||||
MarbleGame.instance.setPreviewMission('urban', () -> {});
|
||||
var pmg = new SPCustomsGui();
|
||||
canvas.setContent(pmg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package src;
|
||||
|
||||
import gui.SPCustomsGui;
|
||||
import net.NetPacket.ScoreboardPacket;
|
||||
import net.NetPacket.PowerupPickupPacket;
|
||||
import net.Move;
|
||||
|
|
@ -255,7 +256,12 @@ class MarbleWorld extends Scheduler {
|
|||
this.scene2d = scene2d;
|
||||
this.mission = mission;
|
||||
this.game = mission.game.toLowerCase();
|
||||
this.gameMode = GameModeFactory.getGameMode(cast this, mission.missionInfo.gamemode);
|
||||
|
||||
var misGameMode = mission.missionInfo != null ? mission.missionInfo.gamemode : null;
|
||||
if (mission.customSource == "MPCustoms")
|
||||
misGameMode = "scrum";
|
||||
|
||||
this.gameMode = GameModeFactory.getGameMode(cast this, misGameMode);
|
||||
this.replay = new Replay(mission.path, mission.isClaMission ? mission.id : 0);
|
||||
this.isRecording = record;
|
||||
this.rewindManager = new RewindManager(cast this);
|
||||
|
|
@ -2236,23 +2242,26 @@ class MarbleWorld extends Scheduler {
|
|||
this.finishYaw = this.marble.camera.CameraYaw;
|
||||
this.finishPitch = this.marble.camera.CameraPitch;
|
||||
displayAlert("Congratulations! You've finished!");
|
||||
if (!Settings.levelStatistics.exists(mission.path)) {
|
||||
Settings.levelStatistics.set(mission.path, {
|
||||
|
||||
var misPath = mission.isClaMission ? 'custom/mbu/${mission.id}' : mission.path;
|
||||
|
||||
if (!Settings.levelStatistics.exists(misPath)) {
|
||||
Settings.levelStatistics.set(misPath, {
|
||||
oobs: 0,
|
||||
respawns: 0,
|
||||
totalTime: 0,
|
||||
totalMPScore: 0
|
||||
});
|
||||
}
|
||||
Analytics.trackLevelScore(mission.title, mission.path,
|
||||
Analytics.trackLevelScore(mission.title, misPath,
|
||||
gameMode.getScoreType() == Time ? Std.int(1000 * gameMode.getFinishScore()) : Std.int(gameMode.getFinishScore()),
|
||||
Settings.levelStatistics[mission.path].oobs, Settings.levelStatistics[mission.path].respawns, Settings.optionsSettings.rewindEnabled);
|
||||
Settings.levelStatistics[misPath].oobs, Settings.levelStatistics[misPath].respawns, Settings.optionsSettings.rewindEnabled);
|
||||
if (!this.isWatching) {
|
||||
var myScore = {
|
||||
name: "Player",
|
||||
time: this.gameMode.getFinishScore()
|
||||
};
|
||||
Settings.saveScore(mission.path, myScore, this.gameMode.getScoreType());
|
||||
Settings.saveScore(misPath, myScore, this.gameMode.getScoreType());
|
||||
var notifies = AchievementsGui.check();
|
||||
var delay = 5.0;
|
||||
var achDelay = 0.0;
|
||||
|
|
@ -2324,10 +2333,16 @@ class MarbleWorld extends Scheduler {
|
|||
}
|
||||
} else {
|
||||
this.dispose();
|
||||
if (mission.isClaMission) {
|
||||
MarbleGame.instance.setPreviewMission('urban', () -> {});
|
||||
var pmg = new SPCustomsGui();
|
||||
MarbleGame.canvas.setContent(pmg);
|
||||
} else {
|
||||
LevelSelectGui.currentSelectionStatic = mission.index + 1;
|
||||
var pmg = new LevelSelectGui(["beginner", "intermediate", "advanced", "multiplayer"][mission.difficultyIndex]);
|
||||
MarbleGame.canvas.setContent(pmg);
|
||||
}
|
||||
}
|
||||
#if js
|
||||
pointercontainer.hidden = false;
|
||||
#end
|
||||
|
|
@ -2361,18 +2376,6 @@ class MarbleWorld extends Scheduler {
|
|||
} else {
|
||||
restartGameCode();
|
||||
}
|
||||
}, (sender) -> {
|
||||
var nextLevelCode = () -> {
|
||||
var nextMission = mission.getNextMission();
|
||||
if (nextMission != null) {
|
||||
MarbleGame.instance.playMission(nextMission);
|
||||
}
|
||||
}
|
||||
if (MarbleGame.instance.toRecord) {
|
||||
MarbleGame.canvas.pushDialog(new ReplayNameDlg(nextLevelCode));
|
||||
} else {
|
||||
nextLevelCode();
|
||||
}
|
||||
}, mission, this.gameMode.getFinishScore(),
|
||||
this.gameMode.getScoreType(), this.replay.write());
|
||||
MarbleGame.canvas.pushDialog(egg);
|
||||
|
|
|
|||
|
|
@ -8,42 +8,51 @@ import src.Mission;
|
|||
import src.Http;
|
||||
import src.ResourceLoader;
|
||||
import src.Console;
|
||||
import src.MarbleGame;
|
||||
|
||||
class Marbleland {
|
||||
public static var goldMissions = [];
|
||||
public static var ultraMissions = [];
|
||||
public static var platinumMissions = [];
|
||||
public static var ultraMissions:Array<Mission> = [];
|
||||
public static var missions:Map<Int, Mission> = [];
|
||||
|
||||
public static function init() {
|
||||
Http.get('https://raw.githubusercontent.com/Vanilagy/MarbleBlast/master/src/assets/customs_gold.json', (b) -> {
|
||||
parseMissionList(b.toString(), "gold");
|
||||
Console.log('Loaded gold customs: ${goldMissions.length}');
|
||||
}, (e) -> {});
|
||||
Http.get('https://raw.githubusercontent.com/Vanilagy/MarbleBlast/master/src/assets/customs_ultra.json', (b) -> {
|
||||
parseMissionList(b.toString(), "ultra");
|
||||
Http.get('https://marbleland.vaniverse.io/api/level/list', (b) -> {
|
||||
parseMissionList(b.toString());
|
||||
Console.log('Loaded ultra customs: ${ultraMissions.length}');
|
||||
}, (e) -> {});
|
||||
Http.get('https://raw.githubusercontent.com/Vanilagy/MarbleBlast/master/src/assets/customs_platinum.json', (b) -> {
|
||||
parseMissionList(b.toString(), "platinum");
|
||||
Console.log('Loaded platinum customs: ${platinumMissions.length}');
|
||||
}, (e) -> {});
|
||||
// Load the marbleland level from JS
|
||||
#if js
|
||||
var urlParams = new js.html.URLSearchParams(js.Browser.window.location.search);
|
||||
var playParam = urlParams.get("play");
|
||||
if (playParam != null) {
|
||||
var intParam = Std.parseInt(playParam);
|
||||
if (intParam != null) {
|
||||
var mission = missions.get(intParam);
|
||||
if (mission != null) {
|
||||
MarbleGame.instance.playMission(mission);
|
||||
}
|
||||
}
|
||||
}
|
||||
#end
|
||||
}, (e) -> {
|
||||
Console.log('Error getting custom list from marbleland.');
|
||||
});
|
||||
}
|
||||
|
||||
static function parseMissionList(s:String, game:String) {
|
||||
static function parseMissionList(s:String) {
|
||||
var claJson:Array<Dynamic> = Json.parse(s);
|
||||
if (game == 'gold') {
|
||||
claJson = claJson.filter(x -> x.modification == 'gold');
|
||||
}
|
||||
if (game == 'platinum') {
|
||||
claJson = claJson.filter(x -> x.gameType == 'single' && (x.gameMode == null || x.gameMode == 'null' || x.gamemode == ''));
|
||||
}
|
||||
if (game == 'ultra') {
|
||||
claJson = claJson.filter(x -> x.gameType == 'single');
|
||||
}
|
||||
var platDupes = new Map();
|
||||
|
||||
for (missionData in claJson) {
|
||||
// filter
|
||||
if (missionData.datablockCompatibility != 'mbw' && missionData.datablockCompatibility != 'mbg')
|
||||
continue;
|
||||
// if (!['gold', 'platinum', 'ultra', 'platinumquest'].contains(missionData.modification))
|
||||
// continue;
|
||||
if (missionData.gameMode != null && !(missionData.gameMode == 'null' || missionData.gameMode.toLowerCase() == 'hunt'))
|
||||
continue;
|
||||
|
||||
var isMultiplayer = missionData.gameType == 'multi';
|
||||
if (isMultiplayer && (missionData.gameMode == null || missionData.gameMode.toLowerCase() != 'hunt'))
|
||||
continue;
|
||||
|
||||
var mission = new Mission();
|
||||
mission.id = missionData.id;
|
||||
mission.path = 'missions/' + missionData.baseName;
|
||||
|
|
@ -56,51 +65,30 @@ class Marbleland {
|
|||
mission.description = missionData.desc != null ? missionData.desc : "";
|
||||
mission.qualifyTime = (missionData.qualifyingTime != null && missionData.qualifyingTime != 0) ? missionData.qualifyingTime / 1000 : Math.POSITIVE_INFINITY;
|
||||
mission.goldTime = missionData.goldTime != null ? missionData.goldTime / 1000 : 0;
|
||||
if (missionData.modification == 'platinumquest')
|
||||
missionData.modification = 'platinum'; // play PQ levels compatible with web pls
|
||||
mission.game = missionData.modification;
|
||||
if (missionData.modification == 'platinum')
|
||||
mission.goldTime = missionData.platinumTime != null ? missionData.platinumTime / 1000 : mission.goldTime;
|
||||
mission.ultimateTime = missionData.ultimateTime != null ? missionData.ultimateTime / 1000 : 0;
|
||||
mission.hasEgg = missionData.hasEgg;
|
||||
mission.isClaMission = true;
|
||||
mission.customSource = "Marbleland";
|
||||
|
||||
if (game == 'platinum') {
|
||||
if (platDupes.exists(mission.title + mission.description))
|
||||
continue;
|
||||
else
|
||||
platDupes.set(mission.title + mission.description, true);
|
||||
var game = missionData.modification;
|
||||
if (isMultiplayer) {
|
||||
game = 'multiplayer';
|
||||
}
|
||||
|
||||
switch (game) {
|
||||
case 'gold':
|
||||
goldMissions.push(mission);
|
||||
case 'ultra':
|
||||
ultraMissions.push(mission);
|
||||
case 'platinum':
|
||||
platinumMissions.push(mission);
|
||||
}
|
||||
|
||||
missions.set(mission.id, mission);
|
||||
}
|
||||
|
||||
// sort according to name
|
||||
switch (game) {
|
||||
case 'gold':
|
||||
goldMissions.sort((x, y) -> x.title > y.title ? 1 : (x.title < y.title ? -1 : 0));
|
||||
for (i in 0...goldMissions.length - 1) {
|
||||
@:privateAccess goldMissions[i].next = goldMissions[i + 1];
|
||||
goldMissions[i].index = i;
|
||||
}
|
||||
@:privateAccess goldMissions[goldMissions.length - 1].next = goldMissions[0];
|
||||
goldMissions[goldMissions.length - 1].index = goldMissions.length - 1;
|
||||
case 'platinum':
|
||||
platinumMissions.sort((x, y) -> x.title > y.title ? 1 : (x.title < y.title ? -1 : 0));
|
||||
for (i in 0...platinumMissions.length - 1) {
|
||||
@:privateAccess platinumMissions[i].next = platinumMissions[i + 1];
|
||||
platinumMissions[i].index = i;
|
||||
}
|
||||
@:privateAccess platinumMissions[platinumMissions.length - 1].next = platinumMissions[0];
|
||||
platinumMissions[platinumMissions.length - 1].index = platinumMissions.length - 1;
|
||||
case 'ultra':
|
||||
ultraMissions.sort((x, y) -> x.title > y.title ? 1 : (x.title < y.title ? -1 : 0));
|
||||
for (i in 0...ultraMissions.length - 1) {
|
||||
@:privateAccess ultraMissions[i].next = ultraMissions[i + 1];
|
||||
|
|
@ -109,7 +97,6 @@ class Marbleland {
|
|||
@:privateAccess ultraMissions[ultraMissions.length - 1].next = ultraMissions[0];
|
||||
ultraMissions[ultraMissions.length - 1].index = ultraMissions.length - 1;
|
||||
}
|
||||
}
|
||||
|
||||
public static function getMissionImage(id:Int, cb:Image->Void) {
|
||||
return Http.get('https://marbleland.vaniverse.io/api/level/${id}/image?width=258&height=194', (imageBytes) -> {
|
||||
|
|
|
|||
158
src/Mission.hx
158
src/Mission.hx
|
|
@ -1,5 +1,10 @@
|
|||
package src;
|
||||
|
||||
import h3d.Vector;
|
||||
import mis.MissionElement.MissionElementTrigger;
|
||||
import shapes.Checkpoint;
|
||||
import mis.MissionElement.MissionElementStaticShape;
|
||||
import mis.MissionElement.MissionElementSky;
|
||||
import src.Http.HttpRequest;
|
||||
import gui.Canvas;
|
||||
import gui.MessageBoxOkDlg;
|
||||
|
|
@ -21,6 +26,7 @@ import src.Console;
|
|||
import src.Marbleland;
|
||||
import src.MarbleGame;
|
||||
import src.Http;
|
||||
import src.MPCustoms;
|
||||
|
||||
class Mission {
|
||||
public var root:MissionElementSimGroup;
|
||||
|
|
@ -41,6 +47,7 @@ class Mission {
|
|||
public var hasEgg:Bool;
|
||||
public var isCustom:Bool;
|
||||
public var marbleAttributes:Map<String, String>;
|
||||
public var customSource:String; // Marbleland or MPCustom
|
||||
|
||||
var next:Mission;
|
||||
|
||||
|
|
@ -83,6 +90,18 @@ class Mission {
|
|||
};
|
||||
|
||||
scanMission(root); // Scan for egg
|
||||
if (this.isClaMission)
|
||||
postProcessFromMarbleland();
|
||||
|
||||
if (this.customSource == "MPCustoms") {
|
||||
// Fill the few details from missionInfo
|
||||
if (missionInfo.time != null && missionInfo.time != "0")
|
||||
this.qualifyTime = MisParser.parseNumber(missionInfo.time) / 1000;
|
||||
if (missionInfo.goldtime != null) {
|
||||
this.goldTime = MisParser.parseNumber(missionInfo.goldtime) / 1000;
|
||||
}
|
||||
this.type = missionInfo.type.toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
public function dispose() {
|
||||
|
|
@ -252,14 +271,151 @@ class Mission {
|
|||
|
||||
public function download(onFinish:Void->Void) {
|
||||
if (this.isClaMission) {
|
||||
if (this.customSource == "Marbleland") {
|
||||
Marbleland.download(this.id, (zipEntries) -> {
|
||||
if (zipEntries != null) {
|
||||
ResourceLoader.loadZip(zipEntries, game);
|
||||
ResourceLoader.loadZip(zipEntries, '');
|
||||
onFinish();
|
||||
} else {
|
||||
MarbleGame.canvas.pushDialog(new MessageBoxOkDlg("Failed to download mission"));
|
||||
}
|
||||
});
|
||||
}
|
||||
if (this.customSource == "MPCustoms") {
|
||||
MPCustoms.download({
|
||||
id: this.id,
|
||||
title: this.title,
|
||||
path: this.path,
|
||||
description: this.description,
|
||||
artist: this.artist
|
||||
}, () -> {
|
||||
onFinish();
|
||||
}, () -> {
|
||||
MarbleGame.canvas.pushDialog(new MessageBoxOkDlg("Failed to download mission"));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function postProcessFromMarbleland() {
|
||||
// Since the mission is from Marbleland, we must postprocess it to port it to MBU formats.
|
||||
|
||||
var skyEl:MissionElementSky = null;
|
||||
|
||||
var processFunctions = [];
|
||||
var cloudType = "none";
|
||||
|
||||
function postprocessMission(simGroup:MissionElementSimGroup) {
|
||||
for (element in simGroup.elements) {
|
||||
if (element._type == MissionElementType.Sky) {
|
||||
// Change the sky!!
|
||||
skyEl = cast(element, MissionElementSky);
|
||||
|
||||
var skyMaterial = skyEl.materiallist.toLowerCase();
|
||||
switch (skyMaterial) {
|
||||
case "~/data/skies/cloudy/cloudy.dml" | "~/data/skies/mbu/sky_beginner.dml":
|
||||
skyEl.materiallist = "~/data/skies/sky_beginner.dml";
|
||||
cloudType = "beginner";
|
||||
|
||||
case "~/data/skies/mbu/sky_intermediate.dml":
|
||||
skyEl.materiallist = "~/data/skies/sky_intermediate.dml";
|
||||
cloudType = "intermediate";
|
||||
|
||||
case "~/data/skies/mbu/sky_advanced.dml":
|
||||
skyEl.materiallist = "~/data/skies/sky_advanced.dml";
|
||||
cloudType = "advanced";
|
||||
}
|
||||
}
|
||||
if (element._type == MissionElementType.StaticShape) {
|
||||
var ss = cast(element, MissionElementStaticShape);
|
||||
|
||||
var db = ss.datablock.toLowerCase();
|
||||
switch (db) {
|
||||
case "clear":
|
||||
skyEl.materiallist = "~/data/skies/sky_beginner.dml";
|
||||
cloudType = "beginner";
|
||||
|
||||
case "dusk":
|
||||
skyEl.materiallist = "~/data/skies/sky_intermediate.dml";
|
||||
cloudType = "intermediate";
|
||||
|
||||
case "wintry":
|
||||
skyEl.materiallist = "~/data/skies/sky_advanced.dml";
|
||||
cloudType = "advanced";
|
||||
}
|
||||
}
|
||||
if (element._type == MissionElementType.TSStatic) {
|
||||
var ts = cast(element, mis.MissionElement.MissionElementTSStatic);
|
||||
var shapeName = ts.shapename.toLowerCase();
|
||||
switch (shapeName) {
|
||||
case "~/data/shapes/buttons/checkpoint.dts":
|
||||
// This one needs to be changed to a "checkpoint"
|
||||
var sg = simGroup;
|
||||
processFunctions.push(() -> {
|
||||
// First remove this element
|
||||
sg.elements.remove(ts);
|
||||
// Then add add the actual checkpoint shape
|
||||
var checkpointEl = new MissionElementStaticShape();
|
||||
checkpointEl._name = ts._name;
|
||||
checkpointEl.position = ts.position;
|
||||
checkpointEl.rotation = ts.rotation;
|
||||
checkpointEl.scale = ts.scale;
|
||||
checkpointEl.datablock = "checkPointShape";
|
||||
checkpointEl.fields = [];
|
||||
|
||||
// create new simgroup
|
||||
var checkpointSG = new MissionElementSimGroup();
|
||||
checkpointSG._name = null;
|
||||
checkpointSG.elements = [];
|
||||
checkpointSG.elements.push(checkpointEl);
|
||||
checkpointSG.fields = [];
|
||||
|
||||
// Find the checkpoint triggers affecting this checkpoint
|
||||
var affectedTriggers = sg.elements.filter(x -> x._type == MissionElementType.Trigger)
|
||||
.filter(y -> cast(y, MissionElementTrigger).respawnpoint == ts._name);
|
||||
|
||||
for (triggerEl in affectedTriggers) {
|
||||
var trigger = cast(triggerEl, MissionElementTrigger);
|
||||
// remove trigger from its current simgroup
|
||||
sg.elements.remove(trigger);
|
||||
// add trigger to checkpoint simgroup
|
||||
checkpointSG.elements.push(trigger);
|
||||
}
|
||||
|
||||
sg.elements.push(checkpointSG);
|
||||
});
|
||||
}
|
||||
}
|
||||
if (element._type == MissionElementType.Item) {} else if (element._type == MissionElementType.SimGroup) {
|
||||
postprocessMission(cast element);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
postprocessMission(root);
|
||||
|
||||
// Add astrolabe, because it does not exist
|
||||
var astrolabeEl = new MissionElementStaticShape();
|
||||
astrolabeEl._name = "Astrolabe";
|
||||
astrolabeEl.position = "0 0 -600";
|
||||
astrolabeEl.rotation = "1 0 0 0";
|
||||
astrolabeEl.scale = "1 1 1";
|
||||
astrolabeEl.datablock = "astrolabeShape";
|
||||
astrolabeEl.fields = [];
|
||||
root.elements.push(astrolabeEl);
|
||||
|
||||
// Add the clouds
|
||||
var cloudEl = new MissionElementStaticShape();
|
||||
cloudEl._name = "CloudLayer";
|
||||
cloudEl.position = "0 0 0";
|
||||
cloudEl.rotation = "1 0 0 0";
|
||||
cloudEl.scale = "1 1 1";
|
||||
cloudEl.datablock = 'astrolabeClouds${cloudType}Shape';
|
||||
cloudEl.fields = [];
|
||||
root.elements.push(cloudEl);
|
||||
|
||||
for (f in processFunctions) {
|
||||
f();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,6 +76,9 @@ class DifficultySelectGui extends GuiImage {
|
|||
btnList.addButton(0, 'Gem Hunt', (e) -> {
|
||||
MarbleGame.canvas.setContent(new LevelSelectGui("multiplayer"));
|
||||
}, 20);
|
||||
btnList.addButton(0, 'Custom Levels', (e) -> {
|
||||
MarbleGame.canvas.setContent(new SPCustomsGui());
|
||||
});
|
||||
|
||||
var bottomBar = new GuiControl();
|
||||
bottomBar.position = new Vector(0, 590);
|
||||
|
|
|
|||
|
|
@ -22,13 +22,12 @@ class EndGameGui extends GuiImage {
|
|||
var innerCtrl:GuiControl;
|
||||
var endGameWnd:GuiImage;
|
||||
var retryFunc:GuiControl->Void;
|
||||
var nextFunc:GuiControl->Void;
|
||||
var continueFunc:GuiControl->Void;
|
||||
|
||||
var scoreSubmitted:Bool = false;
|
||||
|
||||
public function new(continueFunc:GuiControl->Void, restartFunc:GuiControl->Void, nextLevelFunc:GuiControl->Void, mission:Mission, score:Float,
|
||||
scoreType:ScoreType, replayData:haxe.io.Bytes) {
|
||||
public function new(continueFunc:GuiControl->Void, restartFunc:GuiControl->Void, mission:Mission, score:Float, scoreType:ScoreType,
|
||||
replayData:haxe.io.Bytes) {
|
||||
var res = ResourceLoader.getImage("data/ui/xbox/BG_fadeOutSoftEdge.png").resource.toTile();
|
||||
super(res);
|
||||
this.horizSizing = Width;
|
||||
|
|
@ -37,7 +36,6 @@ class EndGameGui extends GuiImage {
|
|||
this.extent = new Vector(640, 480);
|
||||
this.mission = mission;
|
||||
this.retryFunc = restartFunc;
|
||||
this.nextFunc = nextLevelFunc;
|
||||
this.continueFunc = continueFunc;
|
||||
|
||||
function loadButtonImages(path:String) {
|
||||
|
|
@ -106,8 +104,12 @@ class EndGameGui extends GuiImage {
|
|||
var egResultLeft = new GuiMLText(arial14, mlFontLoader);
|
||||
egResultLeft.position = new Vector(28, 26);
|
||||
egResultLeft.extent = new Vector(180, 100);
|
||||
if (scoreType == Time)
|
||||
if (scoreType == Time) {
|
||||
if (mission.isClaMission)
|
||||
egResultLeft.text.text = '<p align="right"><font color="${beatPar ? "#8DFF8D" : "#FF7575"}">Time:</font><br/><font color="#88BCEE">Par Time:</font><br/><font color="#EBEBEB">My Best Time:</font></p>';
|
||||
else
|
||||
egResultLeft.text.text = '<p align="right"><font color="${beatPar ? "#8DFF8D" : "#FF7575"}">Time:</font><br/><font color="#88BCEE">Par Time:</font><br/><font color="#EBEBEB">Rating:</font><br/><font color="#EBEBEB">My Best Time:</font></p>';
|
||||
}
|
||||
if (scoreType == Score)
|
||||
egResultLeft.text.text = '<p align="right"><font color="#8DFF8D">Score:</font><br/><font color="#EBEBEB">My Best Score:</font></p>';
|
||||
endGameWnd.addChild(egResultLeft);
|
||||
|
|
@ -151,8 +153,12 @@ class EndGameGui extends GuiImage {
|
|||
egResultRight.extent = new Vector(180, 100);
|
||||
if (scoreType == Score)
|
||||
egResultRight.text.text = '<font color="#8DFF8D">${Util.formatScore(score)}</font><br/><font color="#EBEBEB">${Util.formatScore(bestScore.time)}</font>';
|
||||
if (scoreType == Time)
|
||||
if (scoreType == Time) {
|
||||
if (mission.isClaMission)
|
||||
egResultRight.text.text = '<font color="${beatPar ? "#8DFF8D" : "#FF7575"}">${Util.formatTime(score)}</font><br/><font color="#88BCEE">${Util.formatTime(mission.qualifyTime)}</font><br/><font color="#EBEBEB">${Util.formatTime(bestScore.time)}</font>';
|
||||
else
|
||||
egResultRight.text.text = '<font color="${beatPar ? "#8DFF8D" : "#FF7575"}">${Util.formatTime(score)}</font><br/><font color="#88BCEE">${Util.formatTime(mission.qualifyTime)}</font><br/><font color="#EBEBEB">${rating}</font><br/><font color="#EBEBEB">${Util.formatTime(bestScore.time)}</font>';
|
||||
}
|
||||
endGameWnd.addChild(egResultRight);
|
||||
|
||||
var bottomBar = new GuiControl();
|
||||
|
|
@ -195,12 +201,15 @@ class EndGameGui extends GuiImage {
|
|||
}
|
||||
bottomBar.addChild(nextButton);
|
||||
var rewindUsed = MarbleGame.instance.world.rewindUsed;
|
||||
|
||||
var misPath = mission.isClaMission ? 'custom/mbu/${mission.id}' : mission.path;
|
||||
|
||||
var submitScore = () -> {
|
||||
var lbScoreValue = score;
|
||||
if (scoreType == Score)
|
||||
lbScoreValue = 1000 - score;
|
||||
Leaderboards.submitScore(mission.path, lbScoreValue, rewindUsed, (needsReplay, ref) -> {
|
||||
if (needsReplay) {
|
||||
Leaderboards.submitScore(misPath, lbScoreValue, rewindUsed, (needsReplay, ref) -> {
|
||||
if (needsReplay && !mission.isClaMission) {
|
||||
Leaderboards.submitReplay(ref, replayData);
|
||||
}
|
||||
});
|
||||
|
|
@ -216,7 +225,7 @@ class EndGameGui extends GuiImage {
|
|||
submitScore();
|
||||
}
|
||||
} else {
|
||||
Leaderboards.getScores(mission.path, rewindUsed ? Rewind : NoRewind, lbscores -> {
|
||||
Leaderboards.getScores(misPath, rewindUsed ? Rewind : NoRewind, lbscores -> {
|
||||
// Score submission criteria
|
||||
// If it is better than our non-rewind score, or better than the top non-rewind score, and we are non rewind, submit it
|
||||
// If it is better than our rewind score, or better than the top rewind score, and we are rewind, submit it
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import src.MissionList;
|
|||
import src.Leaderboards;
|
||||
import src.Replay;
|
||||
import gui.HtmlText;
|
||||
import src.Marbleland;
|
||||
|
||||
class LeaderboardsGui extends GuiImage {
|
||||
var innerCtrl:GuiControl;
|
||||
|
|
@ -124,6 +125,11 @@ class LeaderboardsGui extends GuiImage {
|
|||
var headerText = '<font face="arial12">Rank<offset value="50">Name</offset><offset value="400">Score</offset><offset value="500">Rating</offset><offset value="600">Platform</offset></font>';
|
||||
var playerHeaderText = '<font face="arial12">Rank<offset value="50">Name</offset><offset value="575">Rating</offset></font>';
|
||||
|
||||
if (levelSelectDifficulty == "customs") {
|
||||
headerText = '<font face="arial12">Rank<offset value="50">Name</offset><offset value="500">Score</offset><offset value="600">Platform</offset></font>';
|
||||
playerHeaderText = '<font face="arial12">Rank<offset value="50">Name</offset></font>';
|
||||
}
|
||||
|
||||
var scores = [
|
||||
'<offset value="10">1. </offset><offset value="50">Nardo Polo</offset><offset value="500">99:59:999</offset><offset value="625"><img src="unknown"/></offset>',
|
||||
'<offset value="10">2. </offset><offset value="50">Nardo Polo</offset><offset value="500">99:59:999</offset><offset value="625"><img src="pc"/></offset>',
|
||||
|
|
@ -151,10 +157,17 @@ class LeaderboardsGui extends GuiImage {
|
|||
.concat(MissionList.missionList.get('ultra').get('advanced'))
|
||||
.concat(MissionList.missionList.get('ultra').get('multiplayer'));
|
||||
|
||||
var actualIndex = levelSelectDifficulty != "players" ? allMissions.indexOf(MissionList.missionList.get('ultra').get(levelSelectDifficulty)[index]) : 0;
|
||||
var actualIndex = levelSelectDifficulty != "players"
|
||||
&& levelSelectDifficulty != "customs" ? allMissions.indexOf(MissionList.missionList.get('ultra').get(levelSelectDifficulty)[index]) : 0;
|
||||
|
||||
if (levelSelectDifficulty == "customs")
|
||||
actualIndex = index;
|
||||
|
||||
levelTitle.text.text = 'Level ${actualIndex + 1}';
|
||||
|
||||
if (levelSelectDifficulty == "customs")
|
||||
levelTitle.text.text = '';
|
||||
|
||||
var levelNames = allMissions.map(x -> x.title);
|
||||
|
||||
var scoreCategories = ["Overall", "Rewind", "Non-Rewind"];
|
||||
|
|
@ -164,19 +177,26 @@ class LeaderboardsGui extends GuiImage {
|
|||
levelTitle.text.text = 'Top Players: ${scoreCategories[cast scoreView]}';
|
||||
}
|
||||
|
||||
var currentMission = allMissions[actualIndex];
|
||||
if (levelSelectDifficulty == "customs") {
|
||||
levelTitle.text.text = 'Showing: ${scoreCategories[cast scoreView]}';
|
||||
}
|
||||
|
||||
var currentMission:Mission = null;
|
||||
if (levelSelectDifficulty != "customs")
|
||||
currentMission = allMissions[actualIndex];
|
||||
|
||||
var scoreTok = 0;
|
||||
|
||||
function fetchScores() {
|
||||
var ourToken = scoreTok++;
|
||||
Leaderboards.getScores(currentMission.path, scoreView, (scoreList) -> {
|
||||
Leaderboards.getScores(levelSelectDifficulty != "customs" ? currentMission.path : 'custom/mbu/${index}', scoreView, (scoreList) -> {
|
||||
if (ourToken + 1 != scoreTok)
|
||||
return;
|
||||
var scoreTexts = [];
|
||||
var i = 1;
|
||||
|
||||
var isHuntScore = currentMission.difficultyIndex == 3;
|
||||
var isHuntScore = levelSelectDifficulty != "customs" ? currentMission.difficultyIndex == 3 : Marbleland.missions.get(index)
|
||||
.customSource == "MPCustoms";
|
||||
|
||||
for (score in scoreList) {
|
||||
var scoreText = '<offset value="10">${i}. </offset>
|
||||
|
|
@ -185,6 +205,15 @@ class LeaderboardsGui extends GuiImage {
|
|||
<offset value="400">${isHuntScore ? Std.string(1000 - score.score) : Util.formatTime(score.score)}</offset>
|
||||
<offset value="500">${score.rating}</offset>
|
||||
<offset value="625"><img src="${platformToString(score.platform)}"/></offset>';
|
||||
|
||||
if (levelSelectDifficulty == "customs") {
|
||||
scoreText = '<offset value="10">${i}. </offset>
|
||||
<offset value="50">${score.name}</offset>
|
||||
<offset value="475">${score.rewind > 0 ? "<img src='rewind'/>" : ""}</offset>
|
||||
<offset value="500">${isHuntScore ? Std.string(1000 - score.score) : Util.formatTime(score.score)}</offset>
|
||||
<offset value="625"><img src="${platformToString(score.platform)}"/></offset>';
|
||||
}
|
||||
|
||||
scoreTexts.push(scoreText);
|
||||
i++;
|
||||
}
|
||||
|
|
@ -242,7 +271,7 @@ class LeaderboardsGui extends GuiImage {
|
|||
}
|
||||
levelSelectOpts.setCurrentOption(actualIndex);
|
||||
|
||||
if (levelSelectDifficulty != "players")
|
||||
if (levelSelectDifficulty != "players" && levelSelectDifficulty != "customs")
|
||||
innerCtrl.addChild(levelSelectOpts);
|
||||
|
||||
var bottomBar = new GuiControl();
|
||||
|
|
@ -259,6 +288,9 @@ class LeaderboardsGui extends GuiImage {
|
|||
backButton.gamepadAccelerator = [Settings.gamepadSettings.back];
|
||||
backButton.accelerators = [hxd.Key.ESCAPE, hxd.Key.BACKSPACE];
|
||||
if (levelSelectGui)
|
||||
if (levelSelectDifficulty == "customs")
|
||||
backButton.pressedAction = (e) -> MarbleGame.canvas.setContent(new SPCustomsGui());
|
||||
else
|
||||
backButton.pressedAction = (e) -> MarbleGame.canvas.setContent(new LevelSelectGui(levelSelectDifficulty));
|
||||
else {
|
||||
backButton.pressedAction = (e) -> MarbleGame.canvas.setContent(new LeaderboardsSelectGui());
|
||||
|
|
@ -279,10 +311,14 @@ class LeaderboardsGui extends GuiImage {
|
|||
fetchPlayers();
|
||||
} else
|
||||
fetchScores();
|
||||
|
||||
if (levelSelectDifficulty == "customs") {
|
||||
levelTitle.text.text = 'Showing: ${scoreCategories[cast scoreView]}';
|
||||
}
|
||||
}
|
||||
bottomBar.addChild(changeViewButton);
|
||||
|
||||
if (levelSelectDifficulty != "players") {
|
||||
if (levelSelectDifficulty != "players" && levelSelectDifficulty != "customs") {
|
||||
var replayButton = new GuiXboxButton("Watch Replay", 220);
|
||||
replayButton.position = new Vector(750, 0);
|
||||
replayButton.vertSizing = Bottom;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import src.Replay;
|
|||
import src.Marbleland;
|
||||
import src.MissionList;
|
||||
import src.MarbleGame;
|
||||
import src.MPCustoms;
|
||||
|
||||
class MainMenuGui extends GuiImage {
|
||||
var innerCtrl:GuiControl;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import h3d.Vector;
|
|||
import src.ResourceLoader;
|
||||
import src.Settings;
|
||||
import src.MissionList;
|
||||
import src.MPCustoms;
|
||||
|
||||
class MultiplayerLevelSelectGui extends GuiImage {
|
||||
static var currentSelectionStatic:Int = 0;
|
||||
|
|
|
|||
235
src/gui/SPCustomsGui.hx
Normal file
235
src/gui/SPCustomsGui.hx
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
package gui;
|
||||
|
||||
import modes.GameMode.ScoreType;
|
||||
import src.Marbleland;
|
||||
import src.Console;
|
||||
import net.Net;
|
||||
import net.Net.ServerInfo;
|
||||
import net.MasterServerClient;
|
||||
import hxd.res.BitmapFont;
|
||||
import h3d.Vector;
|
||||
import src.ResourceLoader;
|
||||
import src.MarbleGame;
|
||||
import src.Settings;
|
||||
import src.Mission;
|
||||
import src.MissionList;
|
||||
import src.Util;
|
||||
|
||||
class SPCustomsGui extends GuiImage {
|
||||
var innerCtrl:GuiControl;
|
||||
var serverWnd:GuiImage;
|
||||
|
||||
public function new() {
|
||||
var res = ResourceLoader.getImage("data/ui/xbox/BG_fadeOutSoftEdge.png").resource.toTile();
|
||||
super(res);
|
||||
|
||||
var arial14fontdata = ResourceLoader.getFileEntry("data/font/Arial Bold.fnt");
|
||||
var arial14b = new BitmapFont(arial14fontdata.entry);
|
||||
@:privateAccess arial14b.loader = ResourceLoader.loader;
|
||||
var arial14 = arial14b.toSdfFont(cast 21 * Settings.uiScale, h2d.Font.SDFChannel.MultiChannel);
|
||||
|
||||
this.horizSizing = Width;
|
||||
this.vertSizing = Height;
|
||||
this.position = new Vector();
|
||||
this.extent = new Vector(640, 480);
|
||||
|
||||
#if hl
|
||||
var scene2d = hxd.Window.getInstance();
|
||||
#end
|
||||
#if (js || uwp)
|
||||
var scene2d = MarbleGame.instance.scene2d;
|
||||
#end
|
||||
|
||||
var offsetX = (scene2d.width - 1280) / 2;
|
||||
var offsetY = (scene2d.height - 720) / 2;
|
||||
|
||||
var subX = 640 - (scene2d.width - offsetX) * 640 / scene2d.width;
|
||||
var subY = 480 - (scene2d.height - offsetY) * 480 / scene2d.height;
|
||||
|
||||
innerCtrl = new GuiControl();
|
||||
innerCtrl.position = new Vector(offsetX, offsetY);
|
||||
innerCtrl.extent = new Vector(640 - subX, 480 - subY);
|
||||
innerCtrl.horizSizing = Width;
|
||||
innerCtrl.vertSizing = Height;
|
||||
this.addChild(innerCtrl);
|
||||
|
||||
var custWnd = new GuiImage(ResourceLoader.getResource("data/ui/xbox/helpWindow.png", ResourceLoader.getImage, this.imageResources).toTile());
|
||||
custWnd.horizSizing = Right;
|
||||
custWnd.vertSizing = Bottom;
|
||||
custWnd.position = new Vector(330, 58);
|
||||
custWnd.extent = new Vector(640, 330);
|
||||
innerCtrl.addChild(custWnd);
|
||||
|
||||
var customListScroll = new GuiConsoleScrollCtrl(ResourceLoader.getResource("data/ui/common/osxscroll.png", ResourceLoader.getImage, this.imageResources)
|
||||
.toTile());
|
||||
customListScroll.position = new Vector(25, 22);
|
||||
customListScroll.extent = new Vector(600, 280);
|
||||
customListScroll.scrollToBottom = false;
|
||||
custWnd.addChild(customListScroll);
|
||||
|
||||
var ultraMissions = Marbleland.ultraMissions;
|
||||
|
||||
var curMission = ultraMissions[0];
|
||||
|
||||
var customList = new GuiTextListCtrl(arial14, ultraMissions.map(x -> '${x.title} by ${x.artist}'), 0xFFFFFF);
|
||||
var custSelectedIdx = 0;
|
||||
customList.selectedColor = 0xF29515;
|
||||
customList.selectedFillColor = 0x858585;
|
||||
customList.textColor = 0xFFFFFF;
|
||||
customList.position = new Vector(0, 0);
|
||||
customList.extent = new Vector(550, 2880);
|
||||
customList.scrollable = true;
|
||||
customListScroll.addChild(customList);
|
||||
customListScroll.setScrollMax(customList.calculateFullHeight());
|
||||
|
||||
var bottomBar = new GuiControl();
|
||||
bottomBar.position = new Vector(0, 590);
|
||||
bottomBar.extent = new Vector(640, 200);
|
||||
bottomBar.horizSizing = Width;
|
||||
bottomBar.vertSizing = Bottom;
|
||||
innerCtrl.addChild(bottomBar);
|
||||
|
||||
var backButton = new GuiXboxButton("Back", 160);
|
||||
backButton.position = new Vector(400, 0);
|
||||
backButton.vertSizing = Bottom;
|
||||
backButton.horizSizing = Right;
|
||||
backButton.gamepadAccelerator = [Settings.gamepadSettings.back];
|
||||
backButton.accelerators = [hxd.Key.ESCAPE, hxd.Key.BACKSPACE];
|
||||
backButton.pressedAction = (e) -> MarbleGame.canvas.setContent(new DifficultySelectGui());
|
||||
bottomBar.addChild(backButton);
|
||||
|
||||
var recordButton = new GuiXboxButton("Record", 200);
|
||||
recordButton.position = new Vector(560, 0);
|
||||
recordButton.vertSizing = Bottom;
|
||||
recordButton.horizSizing = Right;
|
||||
recordButton.gamepadAccelerator = [Settings.gamepadSettings.alt1];
|
||||
recordButton.pressedAction = (e) -> {
|
||||
MarbleGame.instance.toRecord = true;
|
||||
MarbleGame.canvas.pushDialog(new MessageBoxOkDlg("The next mission you play will be recorded."));
|
||||
}
|
||||
bottomBar.addChild(recordButton);
|
||||
|
||||
var lbButton = new GuiXboxButton("Leaderboard", 220);
|
||||
lbButton.position = new Vector(750, 0);
|
||||
lbButton.vertSizing = Bottom;
|
||||
lbButton.gamepadAccelerator = [Settings.gamepadSettings.alt2];
|
||||
lbButton.horizSizing = Right;
|
||||
lbButton.pressedAction = (e) -> MarbleGame.canvas.setContent(new LeaderboardsGui(curMission.id, "customs", true));
|
||||
bottomBar.addChild(lbButton);
|
||||
|
||||
var nextButton = new GuiXboxButton("Play", 160);
|
||||
nextButton.position = new Vector(960, 0);
|
||||
nextButton.vertSizing = Bottom;
|
||||
nextButton.horizSizing = Right;
|
||||
nextButton.accelerators = [hxd.Key.ENTER];
|
||||
nextButton.gamepadAccelerator = [Settings.gamepadSettings.alt1];
|
||||
nextButton.pressedAction = (e) -> {
|
||||
MarbleGame.instance.playMission(curMission);
|
||||
};
|
||||
bottomBar.addChild(nextButton);
|
||||
|
||||
var levelWnd = new GuiImage(ResourceLoader.getResource("data/ui/xbox/levelPreviewWindow.png", ResourceLoader.getImage, this.imageResources).toTile());
|
||||
levelWnd.position = new Vector(555, 469);
|
||||
levelWnd.extent = new Vector(535, 137);
|
||||
levelWnd.vertSizing = Bottom;
|
||||
levelWnd.horizSizing = Right;
|
||||
innerCtrl.addChild(levelWnd);
|
||||
|
||||
var statIcon = new GuiImage(ResourceLoader.getResource("data/ui/xbox/statIcon.png", ResourceLoader.getImage, this.imageResources).toTile());
|
||||
statIcon.position = new Vector(29, 54);
|
||||
statIcon.extent = new Vector(20, 20);
|
||||
levelWnd.addChild(statIcon);
|
||||
|
||||
var eggIcon = new GuiImage(ResourceLoader.getResource("data/ui/xbox/eggIcon.png", ResourceLoader.getImage, this.imageResources).toTile());
|
||||
eggIcon.position = new Vector(29, 79);
|
||||
eggIcon.extent = new Vector(20, 20);
|
||||
levelWnd.addChild(eggIcon);
|
||||
|
||||
var c0 = 0xEBEBEB;
|
||||
var c1 = 0x8DFF8D;
|
||||
var c2 = 0x88BCEE;
|
||||
var c3 = 0xFF7575;
|
||||
|
||||
var arial14fontdata = ResourceLoader.getFileEntry("data/font/Arial Bold.fnt");
|
||||
var arial14b = new BitmapFont(arial14fontdata.entry);
|
||||
@:privateAccess arial14b.loader = ResourceLoader.loader;
|
||||
var arial14 = arial14b.toSdfFont(cast 21 * Settings.uiScale, h2d.Font.SDFChannel.MultiChannel);
|
||||
function mlFontLoader(text:String) {
|
||||
return arial14;
|
||||
}
|
||||
|
||||
var levelInfoLeft = new GuiMLText(arial14, mlFontLoader);
|
||||
levelInfoLeft.position = new Vector(69, 54);
|
||||
levelInfoLeft.extent = new Vector(180, 100);
|
||||
levelInfoLeft.text.text = '<p align="right"><font color="#EBEBEB">My Best Time:</font><br/><font color="#EBEBEB">Par Time:</font></p>';
|
||||
levelInfoLeft.text.lineSpacing = 6;
|
||||
levelWnd.addChild(levelInfoLeft);
|
||||
|
||||
var levelInfoMid = new GuiMLText(arial14, mlFontLoader);
|
||||
levelInfoMid.position = new Vector(269, 54);
|
||||
levelInfoMid.extent = new Vector(180, 100);
|
||||
levelInfoMid.text.text = '<p align="left"><font color="#EBEBEB">None</font><br/><font color="#88BCEE">99:59:99</font></p>';
|
||||
levelInfoMid.text.lineSpacing = 6;
|
||||
levelWnd.addChild(levelInfoMid);
|
||||
|
||||
function setLevel(idx:Int) {
|
||||
curMission = ultraMissions[idx];
|
||||
custSelectedIdx = idx;
|
||||
var misPath = 'custom/mbu/${curMission.id}';
|
||||
if (Settings.easterEggs.exists(misPath))
|
||||
eggIcon.bmp.visible = true;
|
||||
else
|
||||
eggIcon.bmp.visible = false;
|
||||
|
||||
var scoreType = curMission.customSource == "MPCustoms" ? ScoreType.Score : ScoreType.Time;
|
||||
|
||||
var myScore = Settings.getScores(misPath);
|
||||
var scoreDisp = "None";
|
||||
if (myScore.length != 0)
|
||||
scoreDisp = scoreType == Time ? Util.formatTime(myScore[0].time) : Util.formatScore(myScore[0].time);
|
||||
var isPar = myScore.length != 0 && myScore[0].time < curMission.qualifyTime;
|
||||
var scoreColor = "#EBEBEB";
|
||||
if (isPar)
|
||||
scoreColor = "#8DFF8D";
|
||||
if (scoreType == Score && myScore.length == 0)
|
||||
scoreColor = "#EBEBEB";
|
||||
if (scoreType == Time) {
|
||||
levelInfoLeft.text.text = '<p align="right"><font color="#EBEBEB">My Best Time:</font><br/><font color="#EBEBEB">Par Time:</font></p>';
|
||||
levelInfoMid.text.text = '<p align="left"><font color="${scoreColor}">${scoreDisp}</font><br/><font color="#88BCEE">${Util.formatTime(curMission.qualifyTime)}</font></p>';
|
||||
}
|
||||
if (scoreType == Score) {
|
||||
levelInfoLeft.text.text = '<p align="right"><font color="#EBEBEB">My Best Score:</font></p>';
|
||||
levelInfoMid.text.text = '<p align="left"><font color="${scoreColor}">${scoreDisp}</font></p>';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
var levelSelectOpts = new GuiXboxOptionsList(6, "Level", ultraMissions.map(x -> x.title));
|
||||
levelSelectOpts.position = new Vector(380, 435);
|
||||
levelSelectOpts.extent = new Vector(815, 94);
|
||||
levelSelectOpts.vertSizing = Bottom;
|
||||
levelSelectOpts.horizSizing = Right;
|
||||
levelSelectOpts.alwaysActive = true;
|
||||
levelSelectOpts.onChangeFunc = setLevel;
|
||||
levelSelectOpts.setCurrentOption(0);
|
||||
setLevel(0);
|
||||
innerCtrl.addChild(levelSelectOpts);
|
||||
|
||||
customList.onSelectedFunc = (idx) -> {
|
||||
setLevel(idx);
|
||||
levelSelectOpts.setCurrentOption(idx);
|
||||
}
|
||||
}
|
||||
|
||||
override function onResize(width:Int, height:Int) {
|
||||
var offsetX = (width - 1280) / 2;
|
||||
var offsetY = (height - 720) / 2;
|
||||
|
||||
var subX = 640 - (width - offsetX) * 640 / width;
|
||||
var subY = 480 - (height - offsetY) * 480 / height;
|
||||
innerCtrl.position = new Vector(offsetX, offsetY);
|
||||
innerCtrl.extent = new Vector(640 - subX, 480 - subY);
|
||||
|
||||
super.onResize(width, height);
|
||||
}
|
||||
}
|
||||
|
|
@ -659,7 +659,10 @@ class HuntMode extends NullMode {
|
|||
name: "Player",
|
||||
time: getFinishScore()
|
||||
};
|
||||
Settings.saveScore(level.mission.path, myScore, getScoreType());
|
||||
|
||||
var misPath = level.mission.isClaMission ? 'custom/mbu/${level.mission.id}' : level.mission.path;
|
||||
|
||||
Settings.saveScore(misPath, myScore, getScoreType());
|
||||
var notifies = AchievementsGui.check();
|
||||
var delay = 5.0;
|
||||
var achDelay = 0.0;
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ class MasterServerClient {
|
|||
#if js
|
||||
static var serverIp = "wss://mbomaster.randomityguy.me:8443";
|
||||
#else
|
||||
static var serverIp = "ws://89.58.58.191:8080";
|
||||
static var serverIp = "ws://51.75.65.148:8080";
|
||||
#end
|
||||
public static var instance:MasterServerClient;
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import src.MarbleGame;
|
|||
import gui.MultiplayerLoadingGui;
|
||||
import src.MissionList;
|
||||
import src.Console;
|
||||
import src.MPCustoms;
|
||||
|
||||
@:build(net.RPCMacro.build())
|
||||
class NetCommands {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ class Gem extends DtsObject {
|
|||
showSequences = false; // Gems actually have an animation for the little shiny thing, but the actual game ignores that. I get it, it was annoying as hell.
|
||||
|
||||
var GEM_COLORS = ["red"];
|
||||
var color = element.datablock.substring("GemItem".length);
|
||||
var color = element.datablock.substring("GemItem".length).toLowerCase();
|
||||
if (color.length == 0)
|
||||
color = GEM_COLORS[Math.floor(Math.random() * GEM_COLORS.length)];
|
||||
this.identifier = "Gem" + color;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue