deterministic gem hunt spawn

This commit is contained in:
RandomityGuy 2023-07-19 01:59:41 +05:30
parent 5cc595bbe7
commit 9a76eecaca
5 changed files with 110 additions and 2 deletions

View file

@ -580,6 +580,7 @@ class MarbleWorld extends Scheduler {
this.playGui.setCenterText('');
this.clearSchedule();
this.outOfBounds = false;
this.gameMode.onRespawn();
AudioManager.playSound(ResourceLoader.getResource('data/sound/spawn_alternate.wav', ResourceLoader.getAudio, this.soundResources));
}

53
src/RandomLCG.hx Normal file
View file

@ -0,0 +1,53 @@
class RandomLCG {
var seed:Int;
static var msSeed:Int = 1376312589;
static var quotient = 127773;
static var remainder = 2836;
public function new(seed = -1) {
this.seed = (seed == -1) ? generateSeed() : seed;
}
inline function generateSeed() {
// A very, VERY crude LCG but good enough to generate
// a nice range of seed values
msSeed = (msSeed * 0x015a4e35) + 1;
msSeed = (msSeed >> 16) & 0x7fff;
return (msSeed);
}
public function setSeed(seed:Int) {
this.seed = seed;
}
public function randInt() {
if (seed <= quotient)
seed = (seed * 16807) % 2147483647;
else {
var high_part:Int = Std.int(seed / quotient);
var low_part = seed % quotient;
var test:Int = (16807 * low_part) - (remainder * high_part);
if (test > 0)
seed = test;
else
seed = test + 2147483647;
}
return seed;
}
public function randFloat() {
return randInt() / 2147483647.0;
}
public function randRange(i:Int, n:Int) {
return (i + (randInt() % (n - i + 1)));
}
public function randRangeF(i:Float, n:Int) {
return (i + (n - i) * randFloat());
}
}

View file

@ -24,6 +24,7 @@ interface GameMode {
public function applyRewindState(state:RewindableState):Void;
public function onTimeExpire():Void;
public function onRestart():Void;
public function onRespawn():Void;
public function onGemPickup(gem:Gem):Void;
public function getPreloadFiles():Array<String>;

View file

@ -1,5 +1,6 @@
package modes;
import hxd.Rand;
import rewind.RewindableState;
import gui.AchievementsGui;
import modes.GameMode.ScoreType;
@ -81,6 +82,8 @@ class HuntState implements RewindableState {
var activeGemSpawnGroup:Array<GemSpawnSphere>;
var activeGems:Array<Gem>;
var points:Int;
var rngState:Int;
var rngState2:Int;
public function new() {}
@ -94,6 +97,8 @@ class HuntState implements RewindableState {
c.activeGemSpawnGroup = activeGemSpawnGroup.copy();
c.points = points;
c.activeGems = activeGems.copy();
c.rngState = rngState;
c.rngState2 = rngState2;
return c;
}
}
@ -109,6 +114,8 @@ class HuntMode extends NullMode {
var activeGems:Array<Gem> = [];
var gemBeams:Array<GemBeam> = [];
var gemToBeamMap:Map<Gem, GemBeam> = [];
var rng:RandomLCG = new RandomLCG(100);
var rng2:RandomLCG = new RandomLCG(100);
var points:Int = 0;
@ -131,7 +138,7 @@ class HuntMode extends NullMode {
};
override function getSpawnTransform() {
var randomSpawn = playerSpawnPoints[Math.floor(Math.random() * playerSpawnPoints.length)];
var randomSpawn = playerSpawnPoints[Math.floor(rng2.randRange(0, playerSpawnPoints.length - 1))];
var spawnPos = MisParser.parseVector3(randomSpawn.position);
spawnPos.x *= -1;
var spawnRot = MisParser.parseRotation(randomSpawn.rotation);
@ -170,6 +177,7 @@ class HuntMode extends NullMode {
var spawnMat = spawnRot.toMatrix();
var up = spawnMat.up();
spawnPos = spawnPos.add(up.multiply(0.727843 / 3)); // 1.5 -> 0.5
return {
position: spawnPos,
orientation: spawnRot,
@ -179,6 +187,26 @@ class HuntMode extends NullMode {
return null;
}
override function onRespawn() {
if (activeGemSpawnGroup.length != 0) {
var gemAvg = new Vector();
for (g in activeGemSpawnGroup) {
gemAvg = gemAvg.add(g.position);
}
gemAvg.scale(1 / activeGemSpawnGroup.length);
var delta = gemAvg.sub(level.marble.getAbsPos().getPosition());
var gravFrame = level.getOrientationQuat(0).toMatrix();
var v1 = gravFrame.front();
var v2 = gravFrame.right();
var deltaRot = new Vector(delta.dot(v2), delta.dot(v1));
if (deltaRot.length() >= 0.001) {
var ang = Math.atan2(deltaRot.x, deltaRot.y);
level.marble.camera.CameraYaw = ang;
level.marble.camera.nextCameraYaw = ang;
}
}
}
override public function getStartTime() {
return level.mission.qualifyTime;
}
@ -188,6 +216,8 @@ class HuntMode extends NullMode {
}
override function onRestart() {
rng.setSeed(100);
rng2.setSeed(100);
setupGems();
points = 0;
@:privateAccess level.playGui.formatGemHuntCounter(points);
@ -242,9 +272,26 @@ class HuntMode extends NullMode {
}
}
}
activeGemSpawnGroup = [];
activeGems = [];
refillGemGroups();
var gemAvg = new Vector();
for (g in activeGemSpawnGroup) {
gemAvg = gemAvg.add(g.position);
}
gemAvg.scale(1 / activeGemSpawnGroup.length);
var delta = gemAvg.sub(level.marble.getAbsPos().getPosition());
var gravFrame = level.getOrientationQuat(0).toMatrix();
var v1 = gravFrame.front();
var v2 = gravFrame.right();
var deltaRot = new Vector(delta.dot(v2), delta.dot(v1));
if (deltaRot.length() >= 0.001) {
var ang = Math.atan2(deltaRot.x, deltaRot.y);
level.marble.camera.CameraYaw = ang;
level.marble.camera.nextCameraYaw = ang;
}
}
function refillGemGroups() {
@ -320,7 +367,7 @@ class HuntMode extends NullMode {
function findGemSpawnGroup(outSpawnPoint:Vector) {
// Pick random spawn point
var rnd:Int = Std.int(Math.random() * gemSpawnPoints.length);
var rnd:Int = Std.int(rng.randRange(0, gemSpawnPoints.length - 1));
if (level.isRecording)
level.replay.recordRandomGenState(rnd);
if (level.isWatching)
@ -394,6 +441,8 @@ class HuntMode extends NullMode {
s.points = points;
s.activeGemSpawnGroup = activeGemSpawnGroup;
s.activeGems = activeGems.copy();
s.rngState = @:privateAccess rng.seed;
s.rngState2 = @:privateAccess rng2.seed;
return s;
}
@ -415,5 +464,7 @@ class HuntMode extends NullMode {
var gemBeam = gemToBeamMap.get(gem);
gemBeam.setHide(false);
}
rng.setSeed(s.rngState);
rng2.setSeed(s.rngState2);
}
}

View file

@ -56,6 +56,8 @@ class NullMode implements GameMode {
public function onRestart() {}
public function onRespawn() {}
public function onGemPickup(gem:Gem) {
this.level.gemCount++;
var string:String;