diff --git a/src/MarbleWorld.hx b/src/MarbleWorld.hx index ca931a02..22868136 100644 --- a/src/MarbleWorld.hx +++ b/src/MarbleWorld.hx @@ -1,5 +1,6 @@ package src; +import shapes.PushButton; import collision.Collision; import src.Replay; import hxd.impl.Air3File.FileSeek; @@ -356,6 +357,7 @@ class MarbleWorld extends Scheduler { // Record/Playback trapdoor and landmine states var tidx = 0; var lidx = 0; + var pidx = 0; for (dtss in this.dtsObjects) { if (dtss is Trapdoor) { var trapdoor:Trapdoor = cast dtss; @@ -378,6 +380,15 @@ class MarbleWorld extends Scheduler { } lidx++; } + if (dtss is PushButton) { + var pushbutton:PushButton = cast dtss; + if (!this.isWatching) { + this.replay.recordPushButtonState(pushbutton.lastContactTime - this.timeState.timeSinceLoad); + } else { + pushbutton.lastContactTime = this.replay.getPushButtonState(pidx) + this.timeState.timeSinceLoad; + } + pidx++; + } } var startquat = this.getStartPositionAndOrientation(); @@ -622,6 +633,8 @@ class MarbleWorld extends Scheduler { shape = new Tornado(); else if (dataBlockLowerCase == "trapdoor") shape = new Trapdoor(); + else if (dataBlockLowerCase == "pushbutton") + shape = new PushButton(); else if (dataBlockLowerCase == "oilslick") shape = new Oilslick(); else { @@ -703,6 +716,8 @@ class MarbleWorld extends Scheduler { shape = new Tornado(); else if (dataBlockLowerCase == "trapdoor") shape = new Trapdoor(); + else if (dataBlockLowerCase == "pushbutton") + shape = new PushButton(); else if (dataBlockLowerCase == "oilslick") shape = new Oilslick(); else { diff --git a/src/Replay.hx b/src/Replay.hx index 97b89fa1..07c64599 100644 --- a/src/Replay.hx +++ b/src/Replay.hx @@ -147,6 +147,7 @@ class ReplayInitialState { var trapdoorLastDirections:Array = []; var trapdoorLastCompletions:Array = []; var landMineDisappearTimes:Array = []; + var pushButtonContactTimes:Array = []; public function new() {} @@ -165,6 +166,10 @@ class ReplayInitialState { for (time in this.landMineDisappearTimes) { bw.writeFloat(time); } + bw.writeInt16(this.pushButtonContactTimes.length); + for (time in this.pushButtonContactTimes) { + bw.writeFloat(time); + } } public function read(br:BytesReader) { @@ -182,6 +187,10 @@ class ReplayInitialState { for (i in 0...landMineCount) { this.landMineDisappearTimes.push(br.readFloat()); } + var pushButtonCount = br.readInt16(); + for (i in 0...pushButtonCount) { + this.pushButtonContactTimes.push(br.readFloat()); + } } } @@ -197,7 +206,7 @@ class Replay { var currentPlaybackFrameIdx:Int; var currentPlaybackTime:Float; - var version:Int = 1; + var version:Int = 6; public function new(mission:String) { this.mission = mission; @@ -255,6 +264,10 @@ class Replay { initialState.landMineDisappearTimes.push(disappearTime); } + public function recordPushButtonState(lastContactTime:Float) { + initialState.pushButtonContactTimes.push(lastContactTime); + } + public function getTrapdoorState(idx:Int) { return { lastContactTime: initialState.trapdoorLastContactTimes[idx], @@ -267,6 +280,10 @@ class Replay { return initialState.landMineDisappearTimes[idx]; } + public function getPushButtonState(idx:Int) { + return initialState.pushButtonContactTimes[idx]; + } + public function clear() { this.frames = []; currentRecordFrame = null; diff --git a/src/shapes/PushButton.hx b/src/shapes/PushButton.hx new file mode 100644 index 00000000..5046ebe7 --- /dev/null +++ b/src/shapes/PushButton.hx @@ -0,0 +1,54 @@ +package shapes; + +import hxd.snd.effect.Spatialization; +import src.TimeState; +import collision.CollisionInfo; +import src.Util; +import src.DtsObject; +import h3d.Vector; +import src.ForceObject; +import src.ResourceLoader; +import src.AudioManager; +import src.MarbleWorld; + +class PushButton extends DtsObject { + var lastContactTime = -1e8; + + public function new() { + super(); + this.dtsPath = "data/shapes/buttons/pushbutton.dts"; + this.isCollideable = true; + this.isTSStatic = false; + this.identifier = "PushButton"; + this.hasNonVisualSequences = true; + this.enableCollideCallbacks = true; + } + + public override function update(timeState:TimeState) { + var currentCompletion = this.getCurrentCompletion(timeState); + + // Override the keyframe + this.sequenceKeyframeOverride.set(this.dts.sequences[0], currentCompletion * (this.dts.sequences[0].numKeyFrames - 1)); + super.update(timeState); + } + + function getCurrentCompletion(timeState:TimeState) { + var elapsed = timeState.timeSinceLoad - this.lastContactTime; + var completion = Util.clamp(elapsed / this.dts.sequences[0].duration, 0, 1); + if (elapsed > 5) + completion = Util.clamp(1 - (elapsed - 5) / this.dts.sequences[0].duration, 0, 1); + return completion; + } + + override function onMarbleContact(time:TimeState, ?contact:CollisionInfo) { + super.onMarbleContact(time, contact); + if (time.timeSinceLoad - this.lastContactTime <= 0) + return; // The trapdoor is queued to open, so don't do anything. + var currentCompletion = this.getCurrentCompletion(time); + + if (currentCompletion == 0) + this.lastContactTime = time.timeSinceLoad; + + // this.level.replay.recordMarbleContact(this); + } +}