mirror of
https://github.com/RandomityGuy/MBHaxe.git
synced 2025-10-30 08:11:25 +00:00
759 lines
22 KiB
Haxe
759 lines
22 KiB
Haxe
package modes;
|
|
|
|
import gui.MPEndGameGui;
|
|
import net.NetCommands;
|
|
import net.BitStream.OutputBitStream;
|
|
import net.NetPacket.GemPickupPacket;
|
|
import net.NetPacket.GemSpawnPacket;
|
|
import octree.IOctreeObject;
|
|
import octree.IOctreeObject.RayIntersectionData;
|
|
import h3d.col.Bounds;
|
|
import octree.IOctreeElement;
|
|
import shapes.GemBeam;
|
|
import h3d.Quat;
|
|
import h3d.Vector;
|
|
import shapes.Gem;
|
|
import mis.MisParser;
|
|
import mis.MissionElement.MissionElementSimGroup;
|
|
import octree.Octree;
|
|
import mis.MissionElement.MissionElementTrigger;
|
|
import mis.MissionElement.MissionElementType;
|
|
import src.Mission;
|
|
import src.Marble;
|
|
import src.AudioManager;
|
|
import src.ResourceLoader;
|
|
import net.Net;
|
|
import src.MarbleGame;
|
|
import src.Util;
|
|
|
|
@:structInit
|
|
@:publicFields
|
|
class GemSpawnPoint implements IOctreeObject {
|
|
var gem:Gem;
|
|
var gemBeam:GemBeam;
|
|
|
|
var boundingBox:Bounds;
|
|
var netIndex:Int;
|
|
|
|
var priority:Int;
|
|
|
|
public function new(vec:Vector, spawn:Gem, netIndex:Int) {
|
|
boundingBox = new Bounds();
|
|
boundingBox.addPoint(vec.add(new Vector(-0.5, -0.5, -0.5)).toPoint());
|
|
boundingBox.addPoint(vec.add(new Vector(0.5, 0.5, 0.5)).toPoint());
|
|
this.gem = spawn;
|
|
this.netIndex = netIndex;
|
|
this.gem.netIndex = netIndex;
|
|
}
|
|
|
|
public function getElementType() {
|
|
return 2;
|
|
}
|
|
|
|
public function setPriority(priority:Int) {
|
|
this.priority = priority;
|
|
}
|
|
|
|
public function rayCast(rayOrigin:Vector, rayDirection:Vector, resultSet:Array<RayIntersectionData>, bestT:Float):Float {
|
|
throw new haxe.exceptions.NotImplementedException(); // Not applicable
|
|
}
|
|
}
|
|
|
|
class HuntMode extends NullMode {
|
|
var playerSpawnPoints:Array<MissionElementTrigger> = [];
|
|
var spawnPointTaken = [];
|
|
var gemOctree:Octree;
|
|
var gemGroupRadius:Float;
|
|
var maxGemsPerGroup:Int;
|
|
var rng:RandomLCG = new RandomLCG(100);
|
|
var rng2:RandomLCG = new RandomLCG(100);
|
|
var gemSpawnPoints:Array<GemSpawnPoint>;
|
|
var lastSpawn:GemSpawnPoint;
|
|
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) {
|
|
var elToRemove = [];
|
|
for (element in simGroup.elements) {
|
|
if ([MissionElementType.Trigger].contains(element._type)) {
|
|
var spawnSphere:MissionElementTrigger = cast element;
|
|
var dbname = spawnSphere.datablock.toLowerCase();
|
|
if (dbname == "spawntrigger") {
|
|
playerSpawnPoints.push(spawnSphere);
|
|
spawnPointTaken.push(false);
|
|
}
|
|
} else if (element._type == MissionElementType.SimGroup) {
|
|
var scanPls = true;
|
|
if (Net.connectedServerInfo.oldSpawns) {
|
|
if (element._name.toLowerCase() == "newversion") {
|
|
// Remove this
|
|
elToRemove.push(element);
|
|
scanPls = false;
|
|
}
|
|
} else {
|
|
if (element._name.toLowerCase() == "oldversion") {
|
|
// Remove this
|
|
elToRemove.push(element);
|
|
scanPls = false;
|
|
}
|
|
}
|
|
if (scanPls)
|
|
scanMission(cast element);
|
|
}
|
|
}
|
|
while (elToRemove.length > 0) {
|
|
simGroup.elements.remove(elToRemove.pop());
|
|
}
|
|
}
|
|
scanMission(mission.root);
|
|
};
|
|
|
|
override function getSpawnTransform() {
|
|
var idx = Net.connectedServerInfo.competitiveMode ? idealSpawnIndex : Math.floor(rng2.randRange(0, playerSpawnPoints.length - 1));
|
|
if (!Net.connectedServerInfo.competitiveMode) {
|
|
var allTaken = true;
|
|
for (spw in spawnPointTaken) {
|
|
if (!spw) {
|
|
allTaken = false;
|
|
break;
|
|
}
|
|
}
|
|
if (!allTaken) {
|
|
while (spawnPointTaken[idx]) {
|
|
idx = Math.floor(rng2.randRange(0, playerSpawnPoints.length - 1));
|
|
}
|
|
spawnPointTaken[idx] = true;
|
|
}
|
|
}
|
|
|
|
var randomSpawn = playerSpawnPoints[idx];
|
|
var spawnPos = MisParser.parseVector3(randomSpawn.position);
|
|
spawnPos.x *= -1;
|
|
var spawnRot = MisParser.parseRotation(randomSpawn.rotation);
|
|
spawnRot.x *= -1;
|
|
spawnRot.w *= -1;
|
|
var spawnMat = spawnRot.toMatrix();
|
|
var up = spawnMat.up();
|
|
|
|
if (MisParser.parseBoolean(randomSpawn.g))
|
|
up.load(up.multiply(-1));
|
|
|
|
spawnPos = spawnPos.add(up); // 1.5 -> 0.5
|
|
return {
|
|
position: spawnPos,
|
|
orientation: spawnRot,
|
|
up: up
|
|
}
|
|
}
|
|
|
|
public function freeSpawns() {
|
|
for (i in 0...playerSpawnPoints.length) {
|
|
spawnPointTaken[i] = false;
|
|
}
|
|
}
|
|
|
|
override function getRespawnTransform(marble:Marble) {
|
|
var lastContactPos = marble.lastContactPosition;
|
|
if (lastContactPos == null) {
|
|
var idx = Math.floor(rng2.randRange(0, playerSpawnPoints.length - 1));
|
|
var randomSpawn = playerSpawnPoints[idx];
|
|
var spawnPos = MisParser.parseVector3(randomSpawn.position);
|
|
spawnPos.x *= -1;
|
|
var spawnRot = MisParser.parseRotation(randomSpawn.rotation);
|
|
spawnRot.x *= -1;
|
|
spawnRot.w *= -1;
|
|
var spawnMat = spawnRot.toMatrix();
|
|
var up = spawnMat.up();
|
|
if (MisParser.parseBoolean(randomSpawn.g))
|
|
up.load(up.multiply(-1));
|
|
|
|
spawnPos = spawnPos.add(up); // 1.5 -> 0.5
|
|
return {
|
|
position: spawnPos,
|
|
orientation: spawnRot,
|
|
up: up
|
|
}
|
|
}
|
|
// Pick closest spawn point
|
|
var closestSpawn:MissionElementTrigger = null;
|
|
var closestDistance = 1e10;
|
|
for (spawn in playerSpawnPoints) {
|
|
var pos = MisParser.parseVector3(spawn.position);
|
|
pos.x *= -1;
|
|
var dist = pos.distance(lastContactPos);
|
|
if (dist < closestDistance) {
|
|
closestDistance = dist;
|
|
closestSpawn = spawn;
|
|
}
|
|
}
|
|
if (closestSpawn != null) {
|
|
var spawnPos = MisParser.parseVector3(closestSpawn.position);
|
|
spawnPos.x *= -1;
|
|
var spawnRot = MisParser.parseRotation(closestSpawn.rotation);
|
|
spawnRot.x *= -1;
|
|
spawnRot.w *= -1;
|
|
var spawnMat = spawnRot.toMatrix();
|
|
var up = spawnMat.up();
|
|
if (MisParser.parseBoolean(closestSpawn.g))
|
|
up.load(up.multiply(-1));
|
|
|
|
spawnPos = spawnPos.add(up); // 1.5 -> 0.5
|
|
|
|
return {
|
|
position: spawnPos,
|
|
orientation: spawnRot,
|
|
up: up
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function prepareGems() {
|
|
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);
|
|
gem.pickedUp = true;
|
|
this.gemSpawnPoints.push(spawn);
|
|
this.gemOctree.insert(spawn);
|
|
gem.setHide(true);
|
|
this.level.collisionWorld.removeEntity(gem.boundingCollider); // remove from octree to make it easy
|
|
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;
|
|
}
|
|
}
|
|
idealSpawnIndex = closestSpawnIndex;
|
|
}
|
|
for (i in 0...spawnPointTaken.length) {
|
|
spawnPointTaken[i] = false;
|
|
}
|
|
}
|
|
|
|
override function getPreloadFiles() {
|
|
return [
|
|
'data/sound/opponentdiamond.wav',
|
|
'data/sound/firewrks.wav',
|
|
'data/shapes/items/blue.gem.png',
|
|
'data/shapes/items/red.gem.png',
|
|
'data/shapes/items/yellow.gem.png',
|
|
'data/shapes/items/platinum.gem.png'
|
|
];
|
|
}
|
|
|
|
function setupGems() {
|
|
hideExisting();
|
|
this.activeGems = [];
|
|
this.activeGemSpawnGroup = [];
|
|
this.rng.setSeed(cast Math.random() * 10000);
|
|
this.rng2.setSeed(cast Math.random() * 10000);
|
|
prepareGems();
|
|
spawnHuntGems();
|
|
}
|
|
|
|
function spawnHuntGems(force:Bool = false) {
|
|
if (activeGems.length != 0 && !force)
|
|
return;
|
|
var gemGroupRadius = 15.0;
|
|
var maxGemsPerSpawn = 7;
|
|
if (level.mission.missionInfo.maxgemsperspawn != null && level.mission.missionInfo.maxgemsperspawn != "")
|
|
maxGemsPerSpawn = Std.parseInt(level.mission.missionInfo.maxgemsperspawn);
|
|
if (level.mission.missionInfo.radiusfromgem != null && level.mission.missionInfo.radiusfromgem != "")
|
|
gemGroupRadius = Std.parseFloat(level.mission.missionInfo.radiusfromgem);
|
|
var spawnBlock = gemGroupRadius * 2;
|
|
if (level.mission.missionInfo.spawnblock != null && level.mission.missionInfo.spawnblock != "")
|
|
spawnBlock = Std.parseFloat(level.mission.missionInfo.spawnblock);
|
|
|
|
var lastPos = null;
|
|
if (lastSpawn != null)
|
|
lastPos = lastSpawn.gem.getAbsPos().getPosition();
|
|
|
|
var furthestDist = 0.0;
|
|
var furthest = null;
|
|
|
|
for (i in 0...6) {
|
|
var gem = gemSpawnPoints[Std.int(rng.randRange(0, gemSpawnPoints.length - 1))];
|
|
if (lastPos != null) {
|
|
var dist = gem.gem.getAbsPos().getPosition().distance(lastPos);
|
|
if (dist < spawnBlock) {
|
|
if (dist > furthestDist) {
|
|
furthestDist = dist;
|
|
furthest = gem;
|
|
}
|
|
continue;
|
|
} else {
|
|
break;
|
|
}
|
|
} else {
|
|
furthest = gem;
|
|
break;
|
|
}
|
|
}
|
|
if (furthest == null) {
|
|
furthest = gemSpawnPoints[Std.int(rng.randRange(0, gemSpawnPoints.length - 1))];
|
|
}
|
|
var pos = furthest.gem.getAbsPos().getPosition();
|
|
|
|
var results = [];
|
|
while (results.length == 0) {
|
|
var search = gemOctree.radiusSearch(pos, gemGroupRadius);
|
|
for (elem in search) {
|
|
var gemElem:GemSpawnPoint = cast elem;
|
|
var gemPos = gemElem.gem.getAbsPos().getPosition();
|
|
|
|
if (level.mission.missionInfo.game == "PlatinumQuest") {
|
|
if (Net.connectedServerInfo.oldSpawns) {
|
|
// Spawn chances!
|
|
var chance = switch (gemElem.gem.gemColor.toLowerCase()) {
|
|
case "red.gem":
|
|
level.mission.missionInfo.spawnchancered != null ? Std.parseFloat(level.mission.missionInfo.spawnchancered) : 0.9;
|
|
case "yellow.gem":
|
|
level.mission.missionInfo.spawnchanceyellow != null ? Std.parseFloat(level.mission.missionInfo.spawnchanceyellow) : 0.65;
|
|
case "blue.gem":
|
|
level.mission.missionInfo.spawnchanceblue != null ? Std.parseFloat(level.mission.missionInfo.spawnchanceblue) : 0.35;
|
|
case "platinum.gem":
|
|
level.mission.missionInfo.spawnchanceplatinum != null ? Std.parseFloat(level.mission.missionInfo.spawnchanceplatinum) : 0.18;
|
|
default:
|
|
1.0;
|
|
};
|
|
var choice = Math.random();
|
|
if (choice > chance)
|
|
continue; // Don't spawn!
|
|
} else {
|
|
// Spawn chances!
|
|
var chance = switch (gemElem.gem.gemColor.toLowerCase()) {
|
|
case "red.gem":
|
|
level.mission.missionInfo.redspawnchance != null ? Std.parseFloat(level.mission.missionInfo.redspawnchance) : 0.9;
|
|
case "yellow.gem":
|
|
level.mission.missionInfo.yellowspawnchance != null ? Std.parseFloat(level.mission.missionInfo.yellowspawnchance) : 0.65;
|
|
case "blue.gem":
|
|
level.mission.missionInfo.bluespawnchance != null ? Std.parseFloat(level.mission.missionInfo.bluespawnchance) : 0.35;
|
|
case "platinum.gem":
|
|
level.mission.missionInfo.platinumspawnchance != null ? Std.parseFloat(level.mission.missionInfo.platinumspawnchance) : 0.18;
|
|
default:
|
|
1.0;
|
|
};
|
|
var choice = Math.random();
|
|
if (choice > chance)
|
|
continue; // Don't spawn!
|
|
}
|
|
}
|
|
|
|
results.push({
|
|
gem: gemElem.netIndex,
|
|
weight: this.gemGroupRadius - gemPos.distance(pos) + rng.randRange(0, getGemWeight(gemElem.gem) + 3)
|
|
});
|
|
}
|
|
}
|
|
results.sort((a, b) -> {
|
|
if (a.weight > b.weight)
|
|
return -1;
|
|
if (a.weight < b.weight)
|
|
return 1;
|
|
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);
|
|
}
|
|
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 = 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);
|
|
}
|
|
|
|
lastSpawn = furthest;
|
|
}
|
|
|
|
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 (!expired) {
|
|
if (gem.gemBeam == null) {
|
|
gem.gemBeam = new GemBeam(StringTools.replace(gem.gem.gemColor, '.gem', ''));
|
|
|
|
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);
|
|
|
|
this.gemToBeamMap.set(gem.gem, gem.gemBeam);
|
|
|
|
level.addDtsObject(gem.gemBeam, () -> {
|
|
// Please be fast lol
|
|
});
|
|
} else {
|
|
gem.gemBeam.setHide(false);
|
|
}
|
|
} else {
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
public inline function setGemHiddenStatus(gemId:Int, status:Bool) {
|
|
var gemSpawn = gemSpawnPoints[gemId];
|
|
if (gemSpawn.gem != null) {
|
|
gemSpawn.gem.pickedUp = status;
|
|
gemSpawn.gem.setHide(status);
|
|
|
|
if (expiredGems.exists(gemSpawn.gem)) {
|
|
var blackBeam = gemToBlackBeamMap.get(gemSpawn.gem);
|
|
blackBeam.setHide(status);
|
|
gemSpawn.gemBeam.setHide(true);
|
|
} else {
|
|
gemSpawn.gemBeam.setHide(status);
|
|
}
|
|
if (status)
|
|
this.activeGems.push(gemSpawn.gem);
|
|
else
|
|
this.activeGems.remove(gemSpawn.gem);
|
|
} else {
|
|
throw new haxe.Exception("Setting gem status for non existent gem!");
|
|
}
|
|
}
|
|
|
|
public function setActiveSpawnSphere(gems:Array<Int>, expireds:Array<Bool>) {
|
|
hideExisting();
|
|
expiredGems = [];
|
|
for (i in 0...gems.length) {
|
|
var gem = gems[i];
|
|
spawnGem(gem, expireds[i]);
|
|
if (expireds[i]) {
|
|
expiredGems.set(gemSpawnPoints[gem].gem, true);
|
|
}
|
|
}
|
|
activeGemSpawnGroup = gems;
|
|
}
|
|
|
|
function getGemWeight(gem:Gem) {
|
|
var col = gem.gemColor.toLowerCase();
|
|
if (col == "red.gem")
|
|
return 0;
|
|
if (col == "yellow.gem")
|
|
return 1;
|
|
if (col == "blue.gem")
|
|
return 4;
|
|
if (col == "platinum.gem")
|
|
return 9;
|
|
return 0;
|
|
}
|
|
|
|
function hideExisting() {
|
|
lastSpawn = null;
|
|
if (gemSpawnPoints != null) {
|
|
for (gs in gemSpawnPoints) {
|
|
gs.gem.setHide(true);
|
|
gs.gem.pickedUp = true;
|
|
if (gs.gemBeam != null) {
|
|
gs.gemBeam.setHide(true);
|
|
}
|
|
if (gemToBlackBeamMap.exists(gs.gem)) {
|
|
gemToBlackBeamMap.get(gs.gem).setHide(true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
override public function getStartTime() {
|
|
return level.mission.qualifyTime;
|
|
}
|
|
|
|
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() {
|
|
if (level.finishTime != null)
|
|
return;
|
|
|
|
AudioManager.playSound(ResourceLoader.getResource("data/sound/firewrks.wav", ResourceLoader.getAudio, @:privateAccess level.soundResources));
|
|
// AudioManager.playSound(ResourceLoader.getResource('data/sound/finish.wav', ResourceLoader.getAudio, @:privateAccess level.soundResources));
|
|
level.finishTime = level.timeState.clone();
|
|
level.marble.setMode(Finish);
|
|
level.marble.camera.finish = true;
|
|
level.finishYaw = level.marble.camera.CameraYaw;
|
|
level.finishPitch = level.marble.camera.CameraPitch;
|
|
// if (level.isMultiplayer) {
|
|
// @:privateAccess level.playGui.doMPEndGameMessage();
|
|
// } else {
|
|
// level.displayAlert("Congratulations! You've finished!");
|
|
// }
|
|
level.cancel(@:privateAccess level.oobSchedule);
|
|
level.cancel(@:privateAccess level.marble.oobSchedule);
|
|
for (marble in level.marbles) {
|
|
marble.setMode(Finish);
|
|
level.cancel(@:privateAccess marble.oobSchedule);
|
|
}
|
|
if (Net.isHost)
|
|
NetCommands.timerRanOut();
|
|
|
|
// Stop the ongoing sounds
|
|
if (@:privateAccess level.timeTravelSound != null) {
|
|
@:privateAccess level.timeTravelSound.stop();
|
|
@:privateAccess level.timeTravelSound = null;
|
|
}
|
|
|
|
if (@:privateAccess level.alarmSound != null) {
|
|
@:privateAccess level.alarmSound.stop();
|
|
@:privateAccess level.alarmSound = null;
|
|
}
|
|
|
|
level.schedule(level.timeState.currentAttemptTime + 2, () -> {
|
|
if (Util.isTouchDevice()) {
|
|
MarbleGame.instance.touchInput.setControlsEnabled(false);
|
|
}
|
|
#if js
|
|
var pointercontainer = js.Browser.document.querySelector("#pointercontainer");
|
|
pointercontainer.hidden = false;
|
|
#end
|
|
MarbleGame.canvas.pushDialog(new MPEndGameGui());
|
|
level.setCursorLock(false);
|
|
return 0;
|
|
});
|
|
}
|
|
|
|
override function onGemPickup(marble:Marble, gem:Gem) {
|
|
if ((@:privateAccess !marble.isNetUpdate && Net.isHost) || !Net.isMP) {
|
|
if (marble == level.marble)
|
|
AudioManager.playSound(ResourceLoader.getResource('data/sound/gotgem.wav', ResourceLoader.getAudio, @:privateAccess this.level.soundResources));
|
|
else
|
|
AudioManager.playSound(ResourceLoader.getResource('data/sound/opponentdiamond.wav', ResourceLoader.getAudio,
|
|
@:privateAccess this.level.soundResources));
|
|
}
|
|
activeGems.remove(gem);
|
|
|
|
var wasExpiredGem = false;
|
|
|
|
if (expiredGems.exists(gem)) {
|
|
wasExpiredGem = true;
|
|
}
|
|
if (gemToBlackBeamMap.exists(gem)) {
|
|
gemToBlackBeamMap.get(gem).setHide(true);
|
|
}
|
|
|
|
var beam = gemToBeamMap.get(gem);
|
|
beam.setHide(true);
|
|
|
|
var incr = 0;
|
|
switch (gem.gemColor.toLowerCase()) {
|
|
case "red.gem":
|
|
incr = 1;
|
|
case "yellow.gem":
|
|
incr = 2;
|
|
case "blue.gem":
|
|
incr = 5;
|
|
case "platinum.gem":
|
|
incr = 10;
|
|
}
|
|
|
|
if (@:privateAccess !marble.isNetUpdate) {
|
|
if (marble == level.marble) {
|
|
switch (gem.gemColor.toLowerCase()) {
|
|
case "red.gem":
|
|
points += 1;
|
|
@:privateAccess level.playGui.addMiddleMessage('+1', 0xFF6666);
|
|
case "yellow.gem":
|
|
points += 2;
|
|
@:privateAccess level.playGui.addMiddleMessage('+2', 0xFFFF66);
|
|
case "blue.gem":
|
|
points += 5;
|
|
@:privateAccess level.playGui.addMiddleMessage('+5', 0x6666FF);
|
|
case "platinum.gem":
|
|
points += 10;
|
|
@:privateAccess level.playGui.addMiddleMessage('+10', 0xdddddd);
|
|
}
|
|
if (Net.isHost)
|
|
@:privateAccess level.playGui.formatGemHuntCounter(points);
|
|
}
|
|
}
|
|
|
|
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);
|
|
spawnNextGemCluster();
|
|
}
|
|
}
|
|
|
|
var packet = new GemPickupPacket();
|
|
packet.clientId = @:privateAccess marble.connection == null ? 0 : @:privateAccess marble.connection.id;
|
|
packet.gemId = gem.netIndex;
|
|
packet.serverTicks = level.timeState.ticks;
|
|
packet.scoreIncr = incr;
|
|
var os = new OutputBitStream();
|
|
os.writeByte(GemPickup);
|
|
packet.serialize(os);
|
|
Net.sendPacketToIngame(os);
|
|
|
|
// Settings.playStatistics.totalMPScore += incr;
|
|
|
|
@:privateAccess level.playGui.incrementPlayerScore(packet.clientId, packet.scoreIncr);
|
|
}
|
|
if (wasExpiredGem)
|
|
expiredGems.remove(gem);
|
|
if (this.level.isMultiplayer && Net.isClient) {
|
|
gem.pickUpClient = @:privateAccess marble.connection == null ? Net.clientId : @:privateAccess marble.connection.id;
|
|
}
|
|
if (!this.level.isMultiplayer || Net.isHost) {
|
|
spawnHuntGems();
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|