mirror of
https://github.com/RandomityGuy/MBHaxe.git
synced 2025-10-30 08:11:25 +00:00
competitive mode and small bugfixes
This commit is contained in:
parent
26ed1cb820
commit
f9a58d15a9
13 changed files with 363 additions and 60 deletions
BIN
data/ui/game/timerhuntrespawn.png
Normal file
BIN
data/ui/game/timerhuntrespawn.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
|
|
@ -1861,19 +1861,21 @@ class Marble extends GameObject {
|
|||
|
||||
this.updateRollSound(timeState, contactTime / timeState.dt, this._slipAmount);
|
||||
|
||||
var megaMarbleDurationTicks = Net.connectedServerInfo.competitiveMode ? 156 : 312;
|
||||
|
||||
if (this.megaMarbleUseTick > 0) {
|
||||
if (Net.isHost) {
|
||||
if ((timeState.ticks - this.megaMarbleUseTick) <= 312 && this.megaMarbleUseTick > 0) {
|
||||
if ((timeState.ticks - this.megaMarbleUseTick) <= megaMarbleDurationTicks && this.megaMarbleUseTick > 0) {
|
||||
this._radius = 0.6666;
|
||||
this.collider.radius = 0.6666;
|
||||
} else if ((timeState.ticks - this.megaMarbleUseTick) > 312) {
|
||||
} else if ((timeState.ticks - this.megaMarbleUseTick) > megaMarbleDurationTicks) {
|
||||
this.collider.radius = this._radius = 0.2;
|
||||
this.megaMarbleUseTick = 0;
|
||||
this.netFlags |= MarbleNetFlags.DoMega;
|
||||
}
|
||||
}
|
||||
if (Net.isClient) {
|
||||
if (this.serverTicks - this.megaMarbleUseTick <= 312 && this.megaMarbleUseTick > 0) {
|
||||
if (this.serverTicks - this.megaMarbleUseTick <= megaMarbleDurationTicks && this.megaMarbleUseTick > 0) {
|
||||
this._radius = 0.6666;
|
||||
this.collider.radius = 0.6666;
|
||||
} else {
|
||||
|
|
@ -1887,7 +1889,7 @@ class Marble extends GameObject {
|
|||
}
|
||||
|
||||
if (Net.isMP) {
|
||||
if (m.jump && this.outOfBounds) {
|
||||
if (m.powerup && this.outOfBounds) {
|
||||
this.level.cancel(this.oobSchedule);
|
||||
this.level.restart(cast this);
|
||||
}
|
||||
|
|
@ -1896,7 +1898,7 @@ class Marble extends GameObject {
|
|||
interior.popTickState();
|
||||
}
|
||||
|
||||
if (m.respawn) {
|
||||
if (m.respawn && !Net.connectedServerInfo.competitiveMode) { // Competitive mode disables quick respawning
|
||||
if (timeState.ticks - lastRespawnTick > (25000 >> 5)) {
|
||||
this.level.restart(cast this);
|
||||
lastRespawnTick = timeState.ticks;
|
||||
|
|
@ -2418,17 +2420,19 @@ class Marble extends GameObject {
|
|||
new Vector(1, 1, 1).add(new Vector(Math.abs(this.currentUp.x), Math.abs(this.currentUp.y), Math.abs(this.currentUp.z)).multiply(-0.8)));
|
||||
this.blastTicks = 0;
|
||||
// Now send the impulse to other marbles
|
||||
var strength = blastAmt * (blastAmt > 1 ? blastRechargeShockwaveStrength : blastShockwaveStrength);
|
||||
var ourPos = this.collider.transform.getPosition();
|
||||
for (marble in level.marbles) {
|
||||
if (marble != cast this) {
|
||||
var theirPos = marble.collider.transform.getPosition();
|
||||
var posDiff = ourPos.distance(theirPos);
|
||||
if (posDiff < strength) {
|
||||
var myMod = isMegaMarbleEnabled(timeState) ? 0.7 : 1.0;
|
||||
var theirMod = @:privateAccess marble.isMegaMarbleEnabled(timeState) ? 0.7 : 1.0;
|
||||
var impulse = theirPos.sub(ourPos).normalized().multiply(strength * (theirMod / myMod));
|
||||
marble.applyImpulse(impulse);
|
||||
if (!Net.connectedServerInfo.competitiveMode || blastAmt > 1) { // Competitor mode only allows ultra blasts
|
||||
var strength = blastAmt * (blastAmt > 1 ? blastRechargeShockwaveStrength : blastShockwaveStrength);
|
||||
var ourPos = this.collider.transform.getPosition();
|
||||
for (marble in level.marbles) {
|
||||
if (marble != cast this) {
|
||||
var theirPos = marble.collider.transform.getPosition();
|
||||
var posDiff = ourPos.distance(theirPos);
|
||||
if (posDiff < strength) {
|
||||
var myMod = isMegaMarbleEnabled(timeState) ? 0.7 : 1.0;
|
||||
var theirMod = @:privateAccess marble.isMegaMarbleEnabled(timeState) ? 0.7 : 1.0;
|
||||
var impulse = theirPos.sub(ourPos).normalized().multiply(strength * (theirMod / myMod));
|
||||
marble.applyImpulse(impulse);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2527,15 +2531,16 @@ class Marble extends GameObject {
|
|||
}
|
||||
|
||||
inline function isMegaMarbleEnabled(timeState:TimeState) {
|
||||
var megaMarbleTicks = Net.connectedServerInfo.competitiveMode ? 156 : 312;
|
||||
if (this.level == null)
|
||||
return false;
|
||||
if (!this.level.isMultiplayer) {
|
||||
return timeState.currentAttemptTime - this.megaMarbleEnableTime < 10;
|
||||
} else {
|
||||
if (Net.isHost) {
|
||||
return (megaMarbleUseTick > 0 && (this.level.timeState.ticks - megaMarbleUseTick) <= 312);
|
||||
return (megaMarbleUseTick > 0 && (this.level.timeState.ticks - megaMarbleUseTick) <= megaMarbleTicks);
|
||||
} else {
|
||||
return (megaMarbleUseTick > 0 && (serverTicks - megaMarbleUseTick) <= 312);
|
||||
return (megaMarbleUseTick > 0 && (serverTicks - megaMarbleUseTick) <= megaMarbleTicks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -386,6 +386,7 @@ class MarbleWorld extends Scheduler {
|
|||
this.endPad.generateCollider();
|
||||
if (this.isMultiplayer) {
|
||||
this.playGui.formatGemHuntCounter(0);
|
||||
this.playGui.formatCountdownTimer(0, 0);
|
||||
} else {
|
||||
this.playGui.formatGemCounter(this.gemCount, this.totalGems);
|
||||
}
|
||||
|
|
@ -1684,10 +1685,10 @@ class MarbleWorld extends Scheduler {
|
|||
return -1;
|
||||
}
|
||||
|
||||
public function spawnHuntGemsClientSide(gemIds:Array<Int>) {
|
||||
public function spawnHuntGemsClientSide(gemIds:Array<Int>, expireds:Array<Bool>) {
|
||||
if (this.isMultiplayer && Net.isClient) {
|
||||
var huntMode:HuntMode = cast this.gameMode;
|
||||
huntMode.setActiveSpawnSphere(gemIds);
|
||||
huntMode.setActiveSpawnSphere(gemIds, expireds);
|
||||
// radar.blink();
|
||||
}
|
||||
}
|
||||
|
|
@ -1829,6 +1830,7 @@ class MarbleWorld extends Scheduler {
|
|||
|
||||
ProfilerUI.measure("updateTimer");
|
||||
this.updateTimer(dt);
|
||||
this.gameMode.update(this.timeState);
|
||||
|
||||
if (!this.isMultiplayer) {
|
||||
if ((Key.isPressed(Settings.controlsSettings.respawn) || Gamepad.isPressed(Settings.gamepadSettings.respawn))
|
||||
|
|
@ -2838,7 +2840,7 @@ class MarbleWorld extends Scheduler {
|
|||
this.deselectPowerUp(this.marble); // Always deselect first
|
||||
// Wait a bit to select the powerup to prevent immediately using it incase the user skipped the OOB screen by clicking
|
||||
if (this.checkpointHeldPowerup != null)
|
||||
this.pickUpPowerUp(this.marble, this.checkpointHeldPowerup);
|
||||
this.schedule(this.timeState.currentAttemptTime + 0.5, () -> this.pickUpPowerUp(this.marble, this.checkpointHeldPowerup));
|
||||
AudioManager.playSound(ResourceLoader.getResource('data/sound/spawn.wav', ResourceLoader.getAudio, this.soundResources));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -244,11 +244,11 @@ class Mission {
|
|||
return path;
|
||||
if (ResourceLoader.exists(dirpath + fname))
|
||||
return dirpath + fname;
|
||||
if (game == 'gold') {
|
||||
path = StringTools.replace(path, 'interiors/', 'interiors_mbg/');
|
||||
if (ResourceLoader.exists(path))
|
||||
return path;
|
||||
}
|
||||
|
||||
path = StringTools.replace(path, 'interiors/', 'interiors_mbg/');
|
||||
if (ResourceLoader.exists(path))
|
||||
return path;
|
||||
|
||||
path = StringTools.replace(path, "lbinteriors", "interiors"); // This shit ew
|
||||
if (ResourceLoader.exists(path))
|
||||
return path;
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ typedef ServerSettings = {
|
|||
var password:String;
|
||||
var forceSpectators:Bool;
|
||||
var quickRespawn:Bool;
|
||||
var competitiveMode:Bool;
|
||||
}
|
||||
|
||||
typedef PlayStatistics = {
|
||||
|
|
@ -210,7 +211,8 @@ class Settings {
|
|||
maxPlayers: 8,
|
||||
description: "My cool server",
|
||||
forceSpectators: false,
|
||||
quickRespawn: true
|
||||
quickRespawn: true,
|
||||
competitiveMode: false,
|
||||
}
|
||||
|
||||
public static var levelStatistics:Map<String, PlayStatistics> = [];
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ class MPServerDlg extends GuiImage {
|
|||
var curServerMaxPlayers = Settings.serverSettings.maxPlayers;
|
||||
var curServerForceSpectators = Settings.serverSettings.forceSpectators;
|
||||
var curServerQuickRespawn = Settings.serverSettings.quickRespawn;
|
||||
var curServerCompetitive = Settings.serverSettings.competitiveMode;
|
||||
|
||||
saveBtn.pressedAction = (e) -> {
|
||||
Settings.serverSettings.name = curServerName;
|
||||
|
|
@ -103,6 +104,7 @@ class MPServerDlg extends GuiImage {
|
|||
Settings.serverSettings.maxPlayers = curServerMaxPlayers;
|
||||
Settings.serverSettings.forceSpectators = curServerForceSpectators;
|
||||
Settings.serverSettings.quickRespawn = curServerQuickRespawn;
|
||||
Settings.serverSettings.competitiveMode = curServerCompetitive;
|
||||
if (Net.isHost) {
|
||||
Net.serverInfo.name = curServerName;
|
||||
Net.serverInfo.description = curServerDescription;
|
||||
|
|
@ -110,7 +112,7 @@ class MPServerDlg extends GuiImage {
|
|||
Net.serverInfo.password = curServerPassword;
|
||||
MasterServerClient.instance.sendServerInfo(Net.serverInfo); // Update data on master server
|
||||
NetCommands.sendServerSettings(Settings.serverSettings.name, Settings.serverSettings.description, Settings.serverSettings.quickRespawn,
|
||||
Settings.serverSettings.forceSpectators);
|
||||
Settings.serverSettings.forceSpectators, Settings.serverSettings.competitiveMode);
|
||||
}
|
||||
MarbleGame.canvas.popDialog(this);
|
||||
}
|
||||
|
|
@ -119,7 +121,7 @@ class MPServerDlg extends GuiImage {
|
|||
serverSettingsContainer.vertSizing = Height;
|
||||
serverSettingsContainer.horizSizing = Left;
|
||||
serverSettingsContainer.position = new Vector(16, 65);
|
||||
serverSettingsContainer.extent = new Vector(390, 276);
|
||||
serverSettingsContainer.extent = new Vector(390, 306);
|
||||
this.addChild(serverSettingsContainer);
|
||||
|
||||
var serverName = new GuiText(markerFelt18);
|
||||
|
|
@ -306,5 +308,28 @@ class MPServerDlg extends GuiImage {
|
|||
curServerQuickRespawn = !curServerQuickRespawn;
|
||||
};
|
||||
serverSettingsContainer.addChild(quickRespawnChk);
|
||||
|
||||
var competitive = new GuiText(markerFelt18);
|
||||
competitive.text.text = "Competitive Mode:";
|
||||
competitive.text.textColor = 0xFFFFFF;
|
||||
competitive.text.dropShadow = {
|
||||
dx: 1,
|
||||
dy: 1,
|
||||
alpha: 0.5,
|
||||
color: 0
|
||||
};
|
||||
competitive.position = new Vector(0, 39 * 7);
|
||||
competitive.extent = new Vector(206, 14);
|
||||
serverSettingsContainer.addChild(competitive);
|
||||
|
||||
var competitiveChk = new GuiButton(loadButtonImages("data/ui/mp/lb_chkbx"));
|
||||
competitiveChk.position = new Vector(359, 9 * 4 + 29 * 8 + 4);
|
||||
competitiveChk.extent = new Vector(31, 31);
|
||||
competitiveChk.buttonType = Toggle;
|
||||
competitiveChk.pressed = curServerCompetitive;
|
||||
competitiveChk.pressedAction = (sender) -> {
|
||||
curServerCompetitive = !curServerCompetitive;
|
||||
};
|
||||
serverSettingsContainer.addChild(competitiveChk);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,6 +62,10 @@ class PlayGui {
|
|||
var timerPoint:GuiAnim;
|
||||
var timerColon:GuiAnim;
|
||||
|
||||
var countdownNumbers:Array<GuiAnim> = [];
|
||||
var countdownPoint:GuiAnim;
|
||||
var countdownIcon:GuiImage;
|
||||
|
||||
var gemCountNumbers:Array<GuiAnim> = [];
|
||||
var gemCountSlash:GuiImage;
|
||||
var gemImageScene:h3d.scene.Scene;
|
||||
|
|
@ -182,8 +186,14 @@ class PlayGui {
|
|||
timerNumbers.push(new GuiAnim(numberTiles));
|
||||
}
|
||||
|
||||
for (i in 0...6) {
|
||||
gemCountNumbers.push(new GuiAnim(numberTiles));
|
||||
if (MarbleGame.instance.world.isMultiplayer) {
|
||||
for (i in 0...3) {
|
||||
countdownNumbers.push(new GuiAnim(numberTiles));
|
||||
}
|
||||
|
||||
for (i in 0...6) {
|
||||
gemCountNumbers.push(new GuiAnim(numberTiles));
|
||||
}
|
||||
}
|
||||
|
||||
var rsgo = [];
|
||||
|
|
@ -211,6 +221,8 @@ class PlayGui {
|
|||
initChatHud();
|
||||
if (Net.hostSpectate || Net.clientSpectate)
|
||||
initSpectatorMenu();
|
||||
|
||||
initGemCountdownTimer();
|
||||
}
|
||||
|
||||
if (Util.isTouchDevice()) {
|
||||
|
|
@ -294,6 +306,44 @@ class PlayGui {
|
|||
playGuiCtrl.addChild(timerCtrl);
|
||||
}
|
||||
|
||||
public function initGemCountdownTimer() {
|
||||
var timerCtrl = new GuiControl();
|
||||
timerCtrl.horizSizing = HorizSizing.Center;
|
||||
timerCtrl.position = new Vector(215, 1);
|
||||
timerCtrl.extent = new Vector(374, 58);
|
||||
|
||||
countdownNumbers[0].position = new Vector(33, 10);
|
||||
countdownNumbers[0].extent = new Vector(28, 37);
|
||||
|
||||
countdownNumbers[1].position = new Vector(49, 10);
|
||||
countdownNumbers[1].extent = new Vector(28, 37);
|
||||
|
||||
var pointCols = [
|
||||
ResourceLoader.getResource('data/ui/game/numbers/point.png', ResourceLoader.getImage, this.imageResources).toTile(),
|
||||
ResourceLoader.getResource('data/ui/game/numbers/point_green.png', ResourceLoader.getImage, this.imageResources).toTile(),
|
||||
ResourceLoader.getResource('data/ui/game/numbers/point_red.png', ResourceLoader.getImage, this.imageResources).toTile()
|
||||
];
|
||||
|
||||
countdownPoint = new GuiAnim(pointCols);
|
||||
countdownPoint.position = new Vector(59, 10);
|
||||
countdownPoint.extent = new Vector(28, 37);
|
||||
|
||||
countdownNumbers[2].position = new Vector(70, 10);
|
||||
countdownNumbers[2].extent = new Vector(28, 37);
|
||||
|
||||
countdownIcon = new GuiImage(ResourceLoader.getResource("data/ui/game/timerhuntrespawn.png", ResourceLoader.getImage, this.imageResources).toTile());
|
||||
countdownIcon.position = new Vector(0, 10);
|
||||
countdownIcon.extent = new Vector(36, 36);
|
||||
|
||||
timerCtrl.addChild(countdownIcon);
|
||||
timerCtrl.addChild(countdownNumbers[0]);
|
||||
timerCtrl.addChild(countdownNumbers[1]);
|
||||
timerCtrl.addChild(countdownPoint);
|
||||
timerCtrl.addChild(countdownNumbers[2]);
|
||||
|
||||
playGuiCtrl.addChild(timerCtrl);
|
||||
}
|
||||
|
||||
public function initCenterText() {
|
||||
RSGOCenterText.x = scene2d.width / 2 - RSGOCenterText.frames[0].width * Settings.uiScale / 2;
|
||||
RSGOCenterText.y = scene2d.height * 0.3; // - RSGOCenterText.frames[0].height / 2;
|
||||
|
|
@ -988,6 +1038,44 @@ class PlayGui {
|
|||
timerColon.anim.currentFrame = color;
|
||||
}
|
||||
|
||||
public function formatCountdownTimer(time:Float, color:Int = 0) {
|
||||
if (time == 0) {
|
||||
countdownNumbers[0].anim.visible = false;
|
||||
countdownNumbers[1].anim.visible = false;
|
||||
countdownNumbers[2].anim.visible = false;
|
||||
countdownPoint.anim.visible = false;
|
||||
countdownIcon.bmp.visible = false;
|
||||
} else {
|
||||
countdownNumbers[0].anim.visible = true;
|
||||
countdownNumbers[1].anim.visible = true;
|
||||
countdownNumbers[2].anim.visible = true;
|
||||
countdownPoint.anim.visible = true;
|
||||
countdownIcon.bmp.visible = true;
|
||||
}
|
||||
|
||||
var et = time * 1000;
|
||||
var hundredth = Math.floor((et % 1000) / 10);
|
||||
var totalSeconds = Math.floor(et / 1000);
|
||||
var seconds = totalSeconds % 60;
|
||||
|
||||
var secondsOne = seconds % 10;
|
||||
var secondsTen = (seconds - secondsOne) / 10;
|
||||
var hundredthOne = hundredth % 10;
|
||||
var hundredthTen = (hundredth - hundredthOne) / 10;
|
||||
|
||||
if (secondsTen > 0) {
|
||||
countdownNumbers[0].anim.visible = true;
|
||||
countdownNumbers[0].anim.currentFrame = secondsTen + color * 10;
|
||||
} else {
|
||||
countdownNumbers[0].anim.visible = false;
|
||||
}
|
||||
|
||||
countdownNumbers[1].anim.currentFrame = secondsOne + color * 10;
|
||||
countdownNumbers[2].anim.currentFrame = hundredthTen + color * 10;
|
||||
|
||||
countdownPoint.anim.currentFrame = color;
|
||||
}
|
||||
|
||||
public function render(engine:h3d.Engine) {
|
||||
engine.pushTarget(this.gemImageSceneTarget);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package modes;
|
||||
|
||||
import src.TimeState;
|
||||
import src.Marble;
|
||||
import shapes.Gem;
|
||||
import h3d.Quat;
|
||||
|
|
@ -27,6 +28,7 @@ interface GameMode {
|
|||
public function onClientRestart():Void;
|
||||
public function onRespawn(marble:Marble):Void;
|
||||
public function onGemPickup(marble:Marble, gem:Gem):Void;
|
||||
public function update(t:TimeState):Void;
|
||||
|
||||
public function getPreloadFiles():Array<String>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,8 +70,13 @@ class HuntMode extends NullMode {
|
|||
var activeGemSpawnGroup:Array<Int>;
|
||||
var gemBeams:Array<GemBeam> = [];
|
||||
var gemToBeamMap:Map<Gem, GemBeam> = [];
|
||||
var gemToBlackBeamMap:Map<Gem, GemBeam> = [];
|
||||
var activeGems:Array<Gem> = [];
|
||||
var points:Int = 0;
|
||||
var gemsCentroid:Vector;
|
||||
var idealSpawnIndex:Int;
|
||||
var expiredGems:Map<Gem, Bool> = [];
|
||||
var competitiveTimerStartTicks:Int;
|
||||
|
||||
override function missionScan(mission:Mission) {
|
||||
function scanMission(simGroup:MissionElementSimGroup) {
|
||||
|
|
@ -92,11 +97,13 @@ class HuntMode extends NullMode {
|
|||
};
|
||||
|
||||
override function getSpawnTransform() {
|
||||
var idx = Math.floor(rng2.randRange(0, playerSpawnPoints.length - 1));
|
||||
while (spawnPointTaken[idx]) {
|
||||
idx = Math.floor(rng2.randRange(0, playerSpawnPoints.length - 1));
|
||||
var idx = Net.connectedServerInfo.competitiveMode ? idealSpawnIndex : Math.floor(rng2.randRange(0, playerSpawnPoints.length - 1));
|
||||
if (!Net.connectedServerInfo.competitiveMode) {
|
||||
while (spawnPointTaken[idx]) {
|
||||
idx = Math.floor(rng2.randRange(0, playerSpawnPoints.length - 1));
|
||||
}
|
||||
spawnPointTaken[idx] = true;
|
||||
}
|
||||
spawnPointTaken[idx] = true;
|
||||
|
||||
var randomSpawn = playerSpawnPoints[idx];
|
||||
var spawnPos = MisParser.parseVector3(randomSpawn.position);
|
||||
|
|
@ -174,6 +181,7 @@ class HuntMode extends NullMode {
|
|||
if (this.gemSpawnPoints == null) {
|
||||
this.gemOctree = new Octree();
|
||||
this.gemSpawnPoints = [];
|
||||
this.gemsCentroid = new Vector();
|
||||
for (gem in this.level.gems) {
|
||||
var spawn:GemSpawnPoint = new GemSpawnPoint(gem.getAbsPos().getPosition(), gem, gemSpawnPoints.length);
|
||||
gem.setHide(true);
|
||||
|
|
@ -185,6 +193,21 @@ class HuntMode extends NullMode {
|
|||
if (level.isMultiplayer) {
|
||||
@:privateAccess level.gemPredictions.alloc();
|
||||
}
|
||||
gemsCentroid.load(gemsCentroid.add(gem.getAbsPos().getPosition()));
|
||||
}
|
||||
if (gemSpawnPoints.length > 0)
|
||||
gemsCentroid.load(gemsCentroid.multiply(1.0 / gemSpawnPoints.length));
|
||||
|
||||
var closestSpawnIndex = 0;
|
||||
var closestSpawnDistance = 1e8;
|
||||
for (i in 0...playerSpawnPoints.length) {
|
||||
var spawn = playerSpawnPoints[i];
|
||||
var spawnPos = MisParser.parseVector3(spawn.position);
|
||||
spawnPos.x *= -1;
|
||||
if (spawnPos.distance(gemsCentroid) < closestSpawnDistance) {
|
||||
closestSpawnDistance = spawnPos.distance(gemsCentroid);
|
||||
closestSpawnIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i in 0...spawnPointTaken.length) {
|
||||
|
|
@ -206,8 +229,8 @@ class HuntMode extends NullMode {
|
|||
spawnHuntGems();
|
||||
}
|
||||
|
||||
function spawnHuntGems() {
|
||||
if (activeGems.length != 0)
|
||||
function spawnHuntGems(force:Bool = false) {
|
||||
if (activeGems.length != 0 && !force)
|
||||
return;
|
||||
var gemGroupRadius = 15.0;
|
||||
var maxGemsPerSpawn = 7;
|
||||
|
|
@ -267,16 +290,39 @@ class HuntMode extends NullMode {
|
|||
return 0;
|
||||
});
|
||||
var spawnSet = results.slice(0, maxGemsPerSpawn).map(x -> x.gem);
|
||||
|
||||
if (force) {
|
||||
for (activeGem in activeGemSpawnGroup)
|
||||
spawnSet.remove(activeGem);
|
||||
}
|
||||
|
||||
for (gem in spawnSet) {
|
||||
spawnGem(gem);
|
||||
}
|
||||
activeGemSpawnGroup = spawnSet;
|
||||
if (!force)
|
||||
activeGemSpawnGroup = spawnSet;
|
||||
else {
|
||||
var uncollectedGems = [];
|
||||
for (g in activeGemSpawnGroup) {
|
||||
if (!gemSpawnPoints[g].gem.pickedUp)
|
||||
uncollectedGems.push(g);
|
||||
}
|
||||
activeGemSpawnGroup = uncollectedGems.concat(spawnSet);
|
||||
}
|
||||
|
||||
if (level.isMultiplayer && Net.isHost) {
|
||||
var bs = new OutputBitStream();
|
||||
bs.writeByte(GemSpawn);
|
||||
var packet = new GemSpawnPacket();
|
||||
packet.gemIds = spawnSet;
|
||||
packet.gemIds = activeGemSpawnGroup;
|
||||
packet.expireds = [];
|
||||
for (i in 0...packet.gemIds.length) {
|
||||
if (expiredGems.exists(gemSpawnPoints[packet.gemIds[i]].gem)) {
|
||||
packet.expireds.push(true);
|
||||
} else {
|
||||
packet.expireds.push(false);
|
||||
}
|
||||
}
|
||||
packet.serialize(bs);
|
||||
Net.sendPacketToIngame(bs);
|
||||
}
|
||||
|
|
@ -284,29 +330,43 @@ class HuntMode extends NullMode {
|
|||
lastSpawn = furthest;
|
||||
}
|
||||
|
||||
function spawnGem(spawn:Int) {
|
||||
function spawnGem(spawn:Int, expired:Bool = false) {
|
||||
var gem = gemSpawnPoints[spawn];
|
||||
gem.gem.setHide(false);
|
||||
gem.gem.pickedUp = false;
|
||||
this.level.collisionWorld.addEntity(gem.gem.boundingCollider);
|
||||
activeGems.push(gem.gem);
|
||||
if (gem.gemBeam == null) {
|
||||
gem.gemBeam = new GemBeam(StringTools.replace(gem.gem.gemColor, '.gem', ''));
|
||||
if (!expired) {
|
||||
if (gem.gemBeam == null) {
|
||||
gem.gemBeam = new GemBeam(StringTools.replace(gem.gem.gemColor, '.gem', ''));
|
||||
|
||||
var gemPos = gem.gem.getAbsPos().getPosition();
|
||||
var gemPos = gem.gem.getAbsPos().getPosition();
|
||||
|
||||
gem.gemBeam.setPosition(gemPos.x, gemPos.y, gemPos.z);
|
||||
gem.gemBeam.setRotationQuat(gem.gem.getRotationQuat().clone());
|
||||
// gem.gemBeam.setOpacity(0.99);
|
||||
this.gemBeams.push(gem.gemBeam);
|
||||
gem.gemBeam.setPosition(gemPos.x, gemPos.y, gemPos.z);
|
||||
gem.gemBeam.setRotationQuat(gem.gem.getRotationQuat().clone());
|
||||
// gem.gemBeam.setOpacity(0.99);
|
||||
this.gemBeams.push(gem.gemBeam);
|
||||
|
||||
this.gemToBeamMap.set(gem.gem, gem.gemBeam);
|
||||
this.gemToBeamMap.set(gem.gem, gem.gemBeam);
|
||||
|
||||
level.addDtsObject(gem.gemBeam, () -> {
|
||||
// Please be fast lol
|
||||
});
|
||||
level.addDtsObject(gem.gemBeam, () -> {
|
||||
// Please be fast lol
|
||||
});
|
||||
} else {
|
||||
gem.gemBeam.setHide(false);
|
||||
}
|
||||
} else {
|
||||
gem.gemBeam.setHide(false);
|
||||
if (gemToBlackBeamMap.exists(gem.gem)) {
|
||||
gemToBlackBeamMap.get(gem.gem).setHide(false);
|
||||
} else {
|
||||
var blackBeam = new GemBeam("black");
|
||||
var pos = gem.gem.getAbsPos().getPosition();
|
||||
blackBeam.setPosition(gem.gem.x, gem.gem.y, gem.gem.z);
|
||||
blackBeam.setRotationQuat(gem.gem.getRotationQuat().clone());
|
||||
blackBeam.setHide(false);
|
||||
level.addDtsObject(blackBeam, () -> {});
|
||||
gemToBlackBeamMap.set(gem.gem, blackBeam);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -325,10 +385,11 @@ class HuntMode extends NullMode {
|
|||
}
|
||||
}
|
||||
|
||||
public function setActiveSpawnSphere(gems:Array<Int>) {
|
||||
public function setActiveSpawnSphere(gems:Array<Int>, expireds:Array<Bool>) {
|
||||
hideExisting();
|
||||
for (gem in gems) {
|
||||
spawnGem(gem);
|
||||
for (i in 0...gems.length) {
|
||||
var gem = gems[i];
|
||||
spawnGem(gem, expireds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -351,6 +412,9 @@ class HuntMode extends NullMode {
|
|||
if (gs.gemBeam != null) {
|
||||
gs.gemBeam.setHide(true);
|
||||
}
|
||||
if (gemToBlackBeamMap.exists(gs.gem)) {
|
||||
gemToBlackBeamMap.get(gs.gem).setHide(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -362,15 +426,18 @@ class HuntMode extends NullMode {
|
|||
override function onRestart() {
|
||||
setupGems();
|
||||
points = 0;
|
||||
competitiveTimerStartTicks = 0;
|
||||
@:privateAccess level.playGui.formatGemHuntCounter(points);
|
||||
}
|
||||
|
||||
override function onMissionLoad() {
|
||||
prepareGems();
|
||||
competitiveTimerStartTicks = 0;
|
||||
}
|
||||
|
||||
override function onClientRestart() {
|
||||
prepareGems();
|
||||
competitiveTimerStartTicks = 0;
|
||||
}
|
||||
|
||||
override function onTimeExpire() {
|
||||
|
|
@ -420,6 +487,17 @@ class HuntMode extends NullMode {
|
|||
@:privateAccess this.level.soundResources));
|
||||
}
|
||||
activeGems.remove(gem);
|
||||
|
||||
var wasExpiredGem = false;
|
||||
|
||||
if (expiredGems.exists(gem)) {
|
||||
wasExpiredGem = true;
|
||||
expiredGems.remove(gem);
|
||||
}
|
||||
if (gemToBlackBeamMap.exists(gem)) {
|
||||
gemToBlackBeamMap.get(gem).setHide(true);
|
||||
}
|
||||
|
||||
var beam = gemToBeamMap.get(gem);
|
||||
beam.setHide(true);
|
||||
|
||||
|
|
@ -455,6 +533,43 @@ class HuntMode extends NullMode {
|
|||
}
|
||||
|
||||
if (this.level.isMultiplayer && Net.isHost) {
|
||||
if (Net.connectedServerInfo.competitiveMode && !wasExpiredGem) {
|
||||
if (competitiveTimerStartTicks == 0) {
|
||||
NetCommands.setCompetitiveTimerStartTicks(this.level.timeState.ticks);
|
||||
}
|
||||
var remaining = 0;
|
||||
for (g in activeGems)
|
||||
if (!expiredGems.exists(g))
|
||||
remaining++;
|
||||
if (remaining == 3) {
|
||||
var currentTime = level.timeState.ticks;
|
||||
var endTime = competitiveTimerStartTicks + (20000 >> 5);
|
||||
var remainingTicks = (endTime - currentTime);
|
||||
if (remainingTicks > (15000 >> 5)) {
|
||||
NetCommands.setCompetitiveTimerStartTicks(currentTime - (5000 >> 5));
|
||||
}
|
||||
}
|
||||
if (remaining == 2) {
|
||||
var currentTime = level.timeState.ticks;
|
||||
var endTime = competitiveTimerStartTicks + (20000 >> 5);
|
||||
var remainingTicks = (endTime - currentTime);
|
||||
if (remainingTicks > (10000 >> 5)) {
|
||||
NetCommands.setCompetitiveTimerStartTicks(currentTime - (10000 >> 5));
|
||||
}
|
||||
}
|
||||
if (remaining == 1) {
|
||||
var currentTime = level.timeState.ticks;
|
||||
var endTime = competitiveTimerStartTicks + (20000 >> 5);
|
||||
var remainingTicks = (endTime - currentTime);
|
||||
if (remainingTicks > (5000 >> 5)) {
|
||||
NetCommands.setCompetitiveTimerStartTicks(currentTime - (15000 >> 5));
|
||||
}
|
||||
}
|
||||
if (remaining == 0) {
|
||||
NetCommands.setCompetitiveTimerStartTicks(0);
|
||||
}
|
||||
}
|
||||
|
||||
var packet = new GemPickupPacket();
|
||||
packet.clientId = @:privateAccess marble.connection == null ? 0 : @:privateAccess marble.connection.id;
|
||||
packet.gemId = gem.netIndex;
|
||||
|
|
@ -474,6 +589,47 @@ class HuntMode extends NullMode {
|
|||
}
|
||||
}
|
||||
|
||||
public function setCompetitiveTimerStartTicks(ticks:Int) {
|
||||
competitiveTimerStartTicks = ticks;
|
||||
}
|
||||
|
||||
function spawnNextGemCluster() {
|
||||
// Expire all existing
|
||||
for (g in activeGems) {
|
||||
expiredGems.set(g, true);
|
||||
var gemBeam = gemToBeamMap.get(g);
|
||||
gemBeam.setHide(true);
|
||||
if (gemToBlackBeamMap.exists(g)) {
|
||||
gemToBlackBeamMap.get(g).setHide(false);
|
||||
} else {
|
||||
var blackBeam = new GemBeam("black");
|
||||
var pos = g.getAbsPos().getPosition();
|
||||
blackBeam.setPosition(g.x, g.y, g.z);
|
||||
blackBeam.setRotationQuat(g.getRotationQuat().clone());
|
||||
blackBeam.setHide(false);
|
||||
level.addDtsObject(blackBeam, () -> {});
|
||||
gemToBlackBeamMap.set(g, blackBeam);
|
||||
}
|
||||
}
|
||||
spawnHuntGems(true);
|
||||
}
|
||||
|
||||
override function update(t:src.TimeState) {
|
||||
if (Net.connectedServerInfo.competitiveMode) {
|
||||
if (competitiveTimerStartTicks != 0) {
|
||||
var currentTime = Net.isHost ? t.ticks : @:privateAccess level.marble.serverTicks;
|
||||
var endTime = competitiveTimerStartTicks + (20000 >> 5);
|
||||
@:privateAccess level.playGui.formatCountdownTimer(Math.max(0, (endTime - currentTime) * 0.032), 0);
|
||||
if (Net.isHost && endTime < currentTime) {
|
||||
spawnNextGemCluster();
|
||||
NetCommands.setCompetitiveTimerStartTicks(0);
|
||||
}
|
||||
} else {
|
||||
@:privateAccess level.playGui.formatCountdownTimer(0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override public function timeMultiplier() {
|
||||
return -1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -138,4 +138,6 @@ class NullMode implements GameMode {
|
|||
public function onClientRestart() {}
|
||||
|
||||
public function onMissionLoad() {}
|
||||
|
||||
public function update(t:src.TimeState) {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ class ConnectedServerInfo {
|
|||
var description:String;
|
||||
var quickRespawn:Bool;
|
||||
var forceSpectator:Bool;
|
||||
var competitiveMode:Bool;
|
||||
}
|
||||
|
||||
class Net {
|
||||
|
|
@ -112,6 +113,13 @@ class Net {
|
|||
clientId = 0;
|
||||
isMP = true;
|
||||
MasterServerClient.instance.sendServerInfo(serverInfo);
|
||||
Net.connectedServerInfo = {
|
||||
name: name,
|
||||
description: description,
|
||||
competitiveMode: Settings.serverSettings.competitiveMode,
|
||||
quickRespawn: Settings.serverSettings.quickRespawn,
|
||||
forceSpectator: Settings.serverSettings.forceSpectators,
|
||||
};
|
||||
onHosted();
|
||||
});
|
||||
}
|
||||
|
|
@ -602,7 +610,7 @@ class Net {
|
|||
// NetCommands.setLobbyCustLevelNameClient(conn, MultiplayerLevelSelectGui.custPath);
|
||||
// } else {
|
||||
NetCommands.sendServerSettingsClient(conn, Settings.serverSettings.name, Settings.serverSettings.description, Settings.serverSettings.quickRespawn,
|
||||
Settings.serverSettings.forceSpectators);
|
||||
Settings.serverSettings.forceSpectators, Settings.serverSettings.competitiveMode);
|
||||
NetCommands.setLobbyLevelIndexClient(conn, MPPlayMissionGui.currentCategoryStatic, MPPlayMissionGui.currentSelectionStatic);
|
||||
// }
|
||||
|
||||
|
|
@ -749,7 +757,7 @@ class Net {
|
|||
var gemSpawnPacket = new GemSpawnPacket();
|
||||
gemSpawnPacket.deserialize(input);
|
||||
if (MarbleGame.instance.world != null && !MarbleGame.instance.world._disposed) {
|
||||
MarbleGame.instance.world.spawnHuntGemsClientSide(gemSpawnPacket.gemIds);
|
||||
MarbleGame.instance.world.spawnHuntGemsClientSide(gemSpawnPacket.gemIds, gemSpawnPacket.expireds);
|
||||
@:privateAccess MarbleGame.instance.world.gemPredictions.acknowledgeGemSpawn(gemSpawnPacket);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -425,12 +425,13 @@ class NetCommands {
|
|||
}
|
||||
}
|
||||
|
||||
@:rpc(server) public static function sendServerSettings(name:String, desc:String, quickRespawn:Bool, forceSpectator:Bool) {
|
||||
@:rpc(server) public static function sendServerSettings(name:String, desc:String, quickRespawn:Bool, forceSpectator:Bool, competitive:Bool) {
|
||||
Net.connectedServerInfo = {
|
||||
name: name,
|
||||
description: desc,
|
||||
quickRespawn: quickRespawn,
|
||||
forceSpectator: forceSpectator
|
||||
forceSpectator: forceSpectator,
|
||||
competitiveMode: competitive
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -452,4 +453,11 @@ class NetCommands {
|
|||
}
|
||||
MPPlayMissionGui.addChatMessage(msg);
|
||||
}
|
||||
|
||||
@:rpc(server) public static function setCompetitiveTimerStartTicks(ticks:Int) {
|
||||
if (MarbleGame.instance.world != null) {
|
||||
var huntMode = cast(MarbleGame.instance.world.gameMode, HuntMode);
|
||||
huntMode.setCompetitiveTimerStartTicks(ticks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -262,15 +262,19 @@ class ExplodableUpdatePacket implements NetPacket {
|
|||
@:publicFields
|
||||
class GemSpawnPacket implements NetPacket {
|
||||
var gemIds:Array<Int>;
|
||||
var expireds:Array<Bool>;
|
||||
|
||||
public function new() {
|
||||
gemIds = [];
|
||||
expireds = [];
|
||||
}
|
||||
|
||||
public function serialize(b:OutputBitStream) {
|
||||
b.writeInt(gemIds.length, 5);
|
||||
for (gemId in gemIds) {
|
||||
for (i in 0...gemIds.length) {
|
||||
var gemId = gemIds[i];
|
||||
b.writeInt(gemId, 11);
|
||||
b.writeFlag(expireds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -278,6 +282,7 @@ class GemSpawnPacket implements NetPacket {
|
|||
var count = b.readInt(5);
|
||||
for (i in 0...count) {
|
||||
gemIds.push(b.readInt(11));
|
||||
expireds.push(b.readFlag());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue