Trigger and PI stuff

This commit is contained in:
RandomityGuy 2021-06-13 20:57:35 +05:30
parent a5704ff8c5
commit 8d47fc0163
10 changed files with 283 additions and 11 deletions

View file

@ -71,10 +71,10 @@ class DifBuilder {
}
];
public static function loadDif(path:String, itr:InteriorObject) {
public static function loadDif(path:String, itr:InteriorObject, ?so:Int = -1) {
var dif = ResourceLoader.loadInterior(path);
var geo = dif.interiors[0];
var geo = so == -1 ? dif.interiors[0] : dif.subObjects[so];
var hulls = geo.convexHulls;

View file

@ -1,5 +1,8 @@
package src;
import src.GameObject;
import triggers.Trigger;
import src.Mission;
import src.TimeState;
import gui.PlayGui;
import src.ParticleSystem.ParticleManager;
@ -34,18 +37,21 @@ class MarbleWorld extends Scheduler {
public var dtsObjects:Array<DtsObject> = [];
var shapeImmunity:Array<DtsObject> = [];
var shapeOrTriggerInside:Array<DtsObject> = [];
var shapeOrTriggerInside:Array<GameObject> = [];
public var timeState:TimeState = new TimeState();
public var bonusTime:Float = 0;
public var sky:Sky;
public var scene:Scene;
public var mission:Mission;
public var marble:Marble;
public var worldOrientation:Quat;
public var currentUp = new Vector(0, 0, 1);
public var outOfBounds:Bool = false;
public var outOfBoundsTime:TimeState;
public var finishTime:TimeState;
var helpTextTimeState:Float = -1e8;
var alertTextTimeState:Float = -1e8;
@ -222,6 +228,13 @@ class MarbleWorld extends Scheduler {
this.alertTextTimeState = this.timeState.currentAttemptTime;
}
public function displayHelp(text:String) {
this.playGui.setHelpText(text);
this.helpTextTimeState = this.timeState.currentAttemptTime;
// TODO FIX
}
function callCollisionHandlers(marble:Marble) {
var contacts = this.collisionWorld.radiusSearch(marble.getAbsPos().getPosition(), marble._radius);
var newImmunity = [];
@ -249,11 +262,25 @@ class MarbleWorld extends Scheduler {
}
shape.onMarbleInside(timeState);
if (!this.shapeOrTriggerInside.contains(shape)) {
this.shapeOrTriggerInside.push(shape);
if (!this.shapeOrTriggerInside.contains(contact.go)) {
this.shapeOrTriggerInside.push(contact.go);
shape.onMarbleEnter(timeState);
}
inside.push(shape);
inside.push(contact.go);
}
if (contact.go is Trigger) {
var trigger:Trigger = cast contact.go;
var contacttest = trigger.collider.sphereIntersection(contactsphere, timeState);
if (contacttest.length != 0) {
trigger.onMarbleContact(timeState);
}
trigger.onMarbleInside(timeState);
if (!this.shapeOrTriggerInside.contains(contact.go)) {
this.shapeOrTriggerInside.push(contact.go);
trigger.onMarbleEnter(timeState);
}
inside.push(contact.go);
}
}
}
@ -333,6 +360,19 @@ class MarbleWorld extends Scheduler {
this.oldOrientationQuat = currentQuat;
this.orientationChangeTime = timeState.currentAttemptTime;
}
public function goOutOfBounds() {
if (this.outOfBounds || this.finishTime != null)
return;
// this.updateCamera(this.timeState); // Update the camera at the point of OOB-ing
this.outOfBounds = true;
this.outOfBoundsTime = this.timeState.clone();
// this.oobCameraPosition = camera.position.clone();
playGui.setCenterText('outofbounds');
// AudioManager.play('whoosh.wav');
// if (this.replay.mode != = 'playback')
this.schedule(this.timeState.currentAttemptTime + 2, () -> this.restart());
}
}
typedef ScheduleInfo = {

13
src/Mission.hx Normal file
View file

@ -0,0 +1,13 @@
package src;
import src.ResourceLoader;
class Mission {
public function getDifPath(rawElementPath:String) {
rawElementPath = rawElementPath.toLowerCase();
var path = rawElementPath;
if (StringTools.contains(path, 'interiors_mbg/'))
path = StringTools.replace(path, 'interiors_mbg/', 'interiors/');
return path;
}
}

View file

@ -1,5 +1,13 @@
package src;
import src.DifBuilder;
import mis.MisParser;
import mis.MissionElement;
import triggers.MustChangeTrigger;
import mis.MissionElement.MissionElementPathedInterior;
import mis.MissionElement.MissionElementSimGroup;
import mis.MissionElement.MissionElementPath;
import h3d.Quat;
import src.TimeState;
import src.MarbleWorld;
import h3d.Matrix;
@ -18,6 +26,11 @@ typedef PIState = {
}
class PathedInterior extends InteriorObject {
var path:MissionElementPath;
var simGroup:MissionElementSimGroup;
var element:MissionElementPathedInterior;
var triggers:Array<MustChangeTrigger> = [];
public var markerData:Array<PathedInteriorMarker> = [];
public var duration:Float;
@ -25,6 +38,10 @@ class PathedInterior extends InteriorObject {
public var targetTime:Float;
public var changeTime:Float;
var basePosition:Vector;
var baseOrientation:Quat;
var baseScale:Vector;
public var prevPosition:Vector;
public var currentPosition:Vector;
@ -33,14 +50,72 @@ class PathedInterior extends InteriorObject {
var stopped:Bool = false;
var stopTime:Float;
public var level:MarbleWorld;
var previousState:PIState;
public static function createFromSimGroup(simGroup:MissionElementSimGroup, level:MarbleWorld) {
var interiorElement:MissionElementPathedInterior = cast simGroup.elements.filter((element) -> element._type == MissionElementType.PathedInterior)[0];
var difFile = level.mission.getDifPath(interiorElement.interiorresource);
if (difFile == null)
return null;
var pathedInterior = new PathedInterior();
pathedInterior.level = level;
DifBuilder.loadDif(difFile, pathedInterior, cast MisParser.parseNumber(interiorElement.interiorindex)); // (difFile, path, level, );
pathedInterior.simGroup = simGroup;
pathedInterior.element = interiorElement;
level.interiors.push(pathedInterior);
// await
// Util.wait(10); // See shapes for the meaning of this hack
// await
pathedInterior.init(level);
return pathedInterior;
}
public function new() {
super();
}
public override function init(level:MarbleWorld) {
this.basePosition = MisParser.parseVector3(this.element.baseposition);
this.baseOrientation = MisParser.parseRotation(this.element.baserotation);
this.baseScale = MisParser.parseVector3(this.element.basescale);
// this.hasCollision = this.baseScale.x != 0
// && this.baseScale.y != = 0 && this.baseScale.z != = 0; // Don't want to add buggy geometry
// Fix zero-volume interiors so they receive correct lighting
if (this.baseScale.x == 0)
this.baseScale.x = 0.0001;
if (this.baseScale.y == 0)
this.baseScale.y = 0.0001;
if (this.baseScale.z == 0)
this.baseScale.z = 0.0001;
this.setRotationQuat(this.baseOrientation);
this.path = cast this.simGroup.elements.filter((element) -> element._type == MissionElementType.Path)[0];
this.markerData = this.path.markers.map(x -> {
var marker = new PathedInteriorMarker();
marker.msToNext = MisParser.parseNumber(x.mstonext) / 1000;
marker.smoothingType = x.smoothingtype;
marker.position = MisParser.parseVector3(x.position);
marker.rotation = MisParser.parseRotation(x.rotation);
return marker;
});
this.computeDuration();
var triggers = this.simGroup.elements.filter((element) -> element._type == MissionElementType.Trigger);
for (triggerElement in triggers) {
var te:MissionElementTrigger = cast triggerElement;
if (te.targettime == null)
continue; // Not a pathed interior trigger
var trigger = new MustChangeTrigger(te, cast this);
this.triggers.push(trigger);
}
this.reset();
}
@ -147,7 +222,10 @@ class PathedInterior extends InteriorObject {
var m2:PathedInteriorMarker = this.markerData[1];
if (m1 == null) {
// Incase there are no markers at all
var mat = this.getTransform();
var mat = new Matrix();
this.baseOrientation.toMatrix(mat);
mat.setPosition(this.basePosition);
mat.scale(this.baseScale.x, this.baseScale.y, this.baseScale.z);
return mat;
} else {
m1 = this.markerData[0];
@ -197,17 +275,32 @@ class PathedInterior extends InteriorObject {
// Offset by the position of the first marker
var firstPosition = this.markerData[0].position;
position.sub(firstPosition);
var tform = this.getTransform().clone();
var basePosition = tform.getPosition();
position.add(basePosition); // Add the base position
tform.setPosition(position);
return tform;
var mat = new Matrix();
this.baseOrientation.toMatrix(mat);
mat.setPosition(position);
mat.scale(this.baseScale.x, this.baseScale.y, this.baseScale.z);
return mat;
}
override function reset() {
this.currentTime = 0;
this.targetTime = -1;
this.changeTime = 0;
if (this.element.initialposition != "") {
this.currentTime = MisParser.parseNumber(this.element.initialposition) / 1000;
}
if (this.element.initialtargetposition != "") {
this.targetTime = MisParser.parseNumber(this.element.initialtargetposition);
// Alright this is strange. In Torque, there are some FPS-dependent client/server desync issues that cause the interior to start at the end position whenever the initialTargetPosition is somewhere greater than 1 and, like, approximately below 50.
if (this.targetTime > 0 && this.targetTime < 50)
this.currentTime = this.duration;
}
this.stopTime = 0;
this.stopped = false;
// Reset the position

View file

@ -230,6 +230,15 @@ class PlayGui {
alertTextBackground.y = scene2d.height - 102 + 1;
}
public function setHelpText(text:String) {
this.helpTextForeground.text = text;
this.helpTextBackground.text = text;
helpTextForeground.x = scene2d.width / 2 - helpTextForeground.textWidth / 2;
helpTextForeground.y = scene2d.height - 102;
helpTextBackground.x = scene2d.width / 2 - helpTextBackground.textWidth / 2 + 1;
helpTextBackground.y = scene2d.height - 102 + 1;
}
public function setPowerupImage(powerupIdentifier:String) {
this.powerupImageScene.removeChildren();
if (powerupIdentifier == "SuperJump") {

View file

@ -0,0 +1,11 @@
package triggers;
import src.TimeState;
class HelpTrigger extends Trigger {
override function onMarbleEnter(timeState:TimeState) {
// AudioManager.play('infotutorial.wav');
this.level.displayHelp(this.element.text);
// this.level.replay.recordMarbleEnter(this);
}
}

View file

@ -0,0 +1,10 @@
package triggers;
import src.TimeState;
class InBoundsTrigger extends Trigger {
override function onMarbleLeave(timeState:TimeState) {
this.level.goOutOfBounds();
// this.level.replay.recordMarbleLeave(this);
}
}

View file

@ -0,0 +1,29 @@
package triggers;
import src.PathedInterior;
import mis.MissionElement.MissionElementTrigger;
import src.TimeState;
import mis.MisParser;
class MustChangeTrigger extends Trigger {
var interior:PathedInterior;
public function new(element:MissionElementTrigger, interior:PathedInterior) {
super(element, interior.level);
this.interior = interior;
}
public override function onMarbleEnter(time:TimeState) {
this.interior.setTargetTime(time, MisParser.parseNumber(this.element.targettime));
if (this.element.instant == "1") {
if (this.element.icontinuetottime != null && this.element.icontinuetottime != "0") {
// Absolutely strange, and not sure if it's even a thing in MBG, but is implement nonetheless.
this.interior.currentTime = this.interior.targetTime;
this.interior.targetTime = MisParser.parseNumber(this.element.icontinuetottime);
} else {
this.interior.changeTime = Math.NEGATIVE_INFINITY; // "If instant is 1, the MP will warp to targetTime instantly."
}
}
// this.level.replay.recordMarbleEnter(this);
}
}

View file

@ -0,0 +1,10 @@
package triggers;
import src.TimeState;
class OutOfBoundsTrigger extends Trigger {
override function onMarbleInside(time:TimeState) {
this.level.goOutOfBounds();
// this.level.replay.recordMarbleInside(this);
}
}

57
src/triggers/Trigger.hx Normal file
View file

@ -0,0 +1,57 @@
package triggers;
import h3d.col.Bounds;
import h3d.Matrix;
import h3d.Vector;
import mis.MisParser;
import collision.BoxCollisionEntity;
import mis.MissionElement.MissionElementTrigger;
import src.GameObject;
import src.MarbleWorld;
class Trigger extends GameObject {
var id:Float;
var level:MarbleWorld;
var element:MissionElementTrigger;
public var collider:BoxCollisionEntity;
public function new(element:MissionElementTrigger, level:MarbleWorld) {
super();
this.element = element;
this.id = element._id;
this.level = level;
var coordinates = MisParser.parseNumberList(element.polyhedron);
var origin = new Vector(coordinates[0], coordinates[1], coordinates[2]);
var d1 = new Vector(coordinates[3], coordinates[4], coordinates[5]);
var d2 = new Vector(coordinates[6], coordinates[7], coordinates[8]);
var d3 = new Vector(coordinates[9], coordinates[10], coordinates[11]);
// Create the 8 points of the parallelepiped
var p1 = origin.clone();
var p2 = origin.add(d1);
var p3 = origin.add(d2);
var p4 = origin.add(d3);
var p5 = origin.add(d1).add(d2);
var p6 = origin.add(d1).add(d3);
var p7 = origin.add(d2).add(d3);
var p8 = origin.add(d1).add(d2).add(d3);
var mat = new Matrix();
var quat = MisParser.parseRotation(element.rotation);
quat.toMatrix(mat);
mat.setPosition(MisParser.parseVector3(element.position));
var scale = MisParser.parseVector3(element.scale);
mat.scale(scale.x, scale.y, scale.z);
var vertices = [p1, p2, p3, p4, p5, p6, p7, p8].map((vert) -> vert.transformed(mat));
var boundingbox = new Bounds();
for (vector in vertices) {
boundingbox.addPoint(vector.toPoint());
}
collider = new BoxCollisionEntity(boundingbox, this);
}
}