Skip to content

The Official Scripting Ask Thread

276 to 300 of 347
Posted April 14, 2020· Edited April 14, 2020

I'm getting better but still new and trying to to do the following:

  1. Activate a track trigger (Successful - Thank you bestdani!)
  2. Print a message to screen to verify trigger hit (Successful - Thank you bestdani!)
  3. Pull harness state (Unsuccessful)
  4. Print harness state to verify
  5. Export harness state outside of NL2 to something (hopefully a text file)

I found the getharnessstate command but I can't get it to work while exporting the response i can't even figure out if there's a command for that at all. Here's what I have so far, what do you think I'm doing wrong?

import com.nolimitscoaster.*;

class TestScript extends Script implements TrackTriggerListener {
    Coaster coaster;
    Section section;
    float HarnessState;
    TrackTrigger trackTrigger;
    TrackTrigger trackTrigger2;
    TrackTrigger trackTrigger3;
    TrackTrigger trackTrigger4;
    TrackTrigger trackTrigger5;
	
    //List off track triggers and listeners
    bool onInit() {
        coaster = sim.getCoasterForEntityId(getParentEntityId());			
	HarnessState = sim.getHarnessState();
        trackTrigger = coaster.getTrackTrigger("StationClear");
        trackTrigger2 = coaster.getTrackTrigger("BBlockOccupied");
	trackTrigger3 = coaster.getTrackTrigger("LiftClear");
	trackTrigger4 = coaster.getTrackTrigger("CBlockOccupied");
	trackTrigger5 = coaster.getTrackTrigger("BBlockClear");
        trackTrigger.addTrackTriggerListener(this);
        trackTrigger2.addTrackTriggerListener(this);
	trackTrigger3.addTrackTriggerListener(this);
	trackTrigger4.addTrackTriggerListener(this);
	trackTrigger5.addTrackTriggerListener(this);
        return true;
    }
	
	//The comments setting output are going to be used for the same
	//thing I'm trying to do with the harnesses but I haven't gotten
	//to implement that either.  I'm having more problems with the
	//harnesses so I'm trying to fix that first.
	public void onTrainEntering(TrackTrigger trigger, Train train) {
	if (trigger == trackTrigger2) {
            System.err.println("B Block Occupied");
	    //int output = 1;
	    //System.err.println(output);
        }
        if (trigger == trackTrigger) {
            System.err.println("Station Clear");
	    harnessState = sim.getHarnessState();
	    System.err.println(harnessState);
        }
	if (trigger == trackTrigger4) {
            System.err.println("C Block Occupied");
        }
    }

	//Same thing here for the output
        public void onTrainLeaving(TrackTrigger trigger, Train train) {
            if (trigger == trackTrigger3) {
            System.err.println("Lift Clear");
        }
	if (trigger == trackTrigger5) {
            System.err.println("B Block Clear");
	    //int output = 0;
	    //System.err.println(output);
        }
    }
}

Well, the Code you'd want to add into the trigger function would be:
train.getHarnessState();

the Problem is that onTrainEntering() and onTrainLeaving() both are only called on the exact frame the Train hits the Trigger, so they're called only once.

The Harnessvalue is a continuous one laying between 0 (fully open) and 1 (fully closed).

so a way to go is to execute a self-set function when the Tracktrigger is hit.

like:

import com.nolimitscoaster.*;

class TestScript extends Script implements TrackTriggerListener {
    Coaster coaster;
    Section section;
    float HarnessState;
    TrackTrigger trackTrigger;
    TrackTrigger trackTrigger2;
    TrackTrigger trackTrigger3;
    TrackTrigger trackTrigger4;
    TrackTrigger trackTrigger5;
    
    bool myFunctionStart = false;
    Train myFunctionTrain;
	
    //List off track triggers and listeners
    bool onInit() {
        coaster = sim.getCoasterForEntityId(getParentEntityId());			
 	HarnessState = sim.getHarnessState();
        trackTrigger = coaster.getTrackTrigger("StationClear");
        trackTrigger2 = coaster.getTrackTrigger("BBlockOccupied");
 	trackTrigger3 = coaster.getTrackTrigger("LiftClear");
 	trackTrigger4 = coaster.getTrackTrigger("CBlockOccupied");
 	trackTrigger5 = coaster.getTrackTrigger("BBlockClear");
        trackTrigger.addTrackTriggerListener(this);
        trackTrigger2.addTrackTriggerListener(this);
 	trackTrigger3.addTrackTriggerListener(this);
 	trackTrigger4.addTrackTriggerListener(this);
 	trackTrigger5.addTrackTriggerListener(this);
        return true;
    }
    public void onNextFrame(float tick)
    {
        if(myFunctionStart)
        {
             HarnessState = myFunctionTrain.getHarnessState();
             System.out.println(HarnessState );
        }
    }
 	//The comments setting output are going to be used for the same
 	//thing I'm trying to do with the harnesses but I haven't gotten
 	//to implement that either.  I'm having more problems with the
 	//harnesses so I'm trying to fix that first.
 	public void onTrainEntering(TrackTrigger trigger, Train train) {
 	if (trigger == trackTrigger2) {
             System.err.println("B Block Occupied");
             myFunctionTrain = train;
             myFunctionStart = true;
 	    //int output = 1;
 	    //System.err.println(output);
         }
         if (trigger == trackTrigger) {
             System.err.println("Station Clear");
 	    harnessState = sim.getHarnessState();
 	    System.err.println(harnessState);
         }
 	if (trigger == trackTrigger4) {
             System.err.println("C Block Occupied");
         }
     }
 
 	//Same thing here for the output
         public void onTrainLeaving(TrackTrigger trigger, Train train) {
             if (trigger == trackTrigger2) {
                 myFunctionTrain = train;
                 myFunctionStart = false;
            }

             if (trigger == trackTrigger3) {
             System.err.println("Lift Clear");
         }
 	if (trigger == trackTrigger5) {
             System.err.println("B Block Clear");
 	    //int output = 0;
 	    //System.err.println(output);
         }
     }
 }

Now you need to reset your bool variable myFunctionStart, otherwise it'll jam your message window all the time.
In this Case doing it with leaving the same Trigger will do the trick.

This already should work for you now

Does anyone have a simple script to play a video (using the default TV screen) at a track trigger point then to turn it off at another point? Cheers :)

I've got some trains using the "Harness the Power Script" I am looking to modify it so that the restraints open-close when the past over a trigger. Is something like this even possible, and if so, would one of you be willing to help me with it or at least point me in the right direction to get started. Thanks

you would just need to gauge when the train hits one of the triggers and then run a method which controls the state of the restrains

import com.nolimitscoaster.*;
import nlvm.math3d.*;
public class HarnessThePower extends Script {

	SceneObject sco;
	SceneObjectElement[] harness;
	
	Train train;
	
	private float[] rand;
	
	public bool onInit(){

		 sco = sim.getSceneObjectForEntityId(getParentEntityId());
	
		Coaster coaster = sim.getCoaster("SR");
	
		train = coaster.findNearestTrain(sco.getTranslation(), 15);
	
		int i2 = 0;
		while(sco.getElementForName("Harness" + i2) != null){
		
			i2++;
		
		}  
		harness = new SceneObjectElement[i2];
		rand = new float[i2];
		
		Vector3f posOut = new Vector3f();
		
		for(int i = 0; i < harness.length; i++){
			
			harness[i] = sco.getElementForName("Harness" + (i));	
			rand[i] = (float)Math.random()/3;
			Tools.matrixToPitchHeadBankPos(harness[i].getMatrix(),  null, posOut);
			
		}
	
		return true;
	
	}

	float rotation = 0;
	
	public void onNextFrame(float tick){
		
		for(int i = 0; i < harness.length; i++){
			
					harness[i].setRotation((float)Tools.switchRampC2(1-rand[i],1.5f,0.2f,train.getHarnessState()),0,0);
		
			
		}
		
	}

}

This is what the trains use right now. Basically just trying to figure out what I need to do so that they are controlled by a trigger instead of the train that they are attached to.

Posted June 23, 2020· Edited June 23, 2020

EDIT :
Never mind got an solution

I'm looking for a script, that can make a surface change color with a Track Trigger

For my current project I would like to use a gate that slides up but I don't understand how to script this. I have asked on several pages before, but no one seems to be able or willing to help.

I have several rotating doors already. I managed to edit the existing script to make the rotating doors operate the way I want them to. So if someone would be willing to convert the existing script from the "Track Trigger Test" object to make the door SLIDE in stead of rotate, I can figure the rest out for myself.

Posted July 13, 2020· Edited July 13, 2020

Unfortunately this script has not been designed in such a way that it would be just some minor change at some single point in the code to do it for every case. But in principle you would have to replace everywhere where .setRotation(...); occurs by .setTranslation(0, rot, 0); for example to slide it along the y axis of the object.

Note that if the element has some inherent translation already this could cause it to jump to some wrong position so it's not something that is absolutely fail safe and this only works that easily if the scene object has been designed to work with that.

So ensure the element that gets animated is a children of another element so that its coordinates are at (0, 0, 0) in the 3d model file and then it should work (maybe you have to move the rot value to another position so that it moves along another axis like .setTranslation(rot, 0, 0); for x axis and .setTranslation(0, 0, rot); for z axis.

In any other case you would need more scripting stuff that reads out the initial position and then some vector math to slide it.

(The best way for things like this imho is using keyframe animations so that the script does not care about the visual representation but just advances the animation which is then part of the 3d model. But this is beyond the scope of this question. But you can find pre made scripts for this already for example in my collection: https://steamcommunity.com/sharedfiles/filedetails/?id=347405277)

Hi! I'm trying to make a script that animates "levitating" objects. For the most part it appears to work, but for some reason the script gets a little buggy whenever I change the sim speed. Specifically, whenever I change the sim speed, since my object is usually at a higher / lower height than its starting position, it treats that as the new "starting" position and ends up levitating higher / lower than the height I intended. Right now I have a quick fix for this, which involves resetting the position of my object whenever I change the sim speed. This technically works and prevents any unwanted changes in my object's position, but obviously it ends up looking a little jarring whenever I change the sim speed (it "teleports" back to its original position). It isn't a huge deal if there's no other way to work around this sim speed issue, but I'm wondering if there's a better way to prevent the issue with this kind of script. Any help would be really appreciated!

import com.nolimitscoaster.*;
public class Levitation extends Script{
	private SceneObject object;
	
	float xPos, yPos, zPos, yPos1;
	float levitation;
	
	float simSpeed, simSpeedPrev;
	
	public final float delay = (float)(2*Math.random());
	float delayCountUp;
	bool goingUp;
	public final float upOrDown = (float)(Math.random());
	
	public bool onInit(){
		int parentID = getParentEntityId();
		object = sim.getSceneObjectForEntityId(parentID);
		xPos = object.getTranslation().x;
		yPos1 = object.getTranslation().y;
		zPos = object.getTranslation().z;
		
		if(upOrDown > 0.5){
			goingUp = true;
		}
		
		return true;
	}
	
	void onNextFrame(float tick){
		simSpeed = sim.getCurSimulationSpeed();
		
		delayCountUp += tick;
		if (delayCountUp >= delay){
			delayCountUp = 3;
			yPos = object.getTranslation().y;
			levitation += tick;
			
			if(goingUp == true){
				object.setTranslation(xPos, (float)(yPos+simSpeed*Math.sin(levitation)/30), zPos);
			}else{
				object.setTranslation(xPos, (float)(yPos-simSpeed*Math.sin(levitation)/30), zPos);
			}
			
			if(((levitation >= Math.PI)&&(yPos/yPos1 <= 1.001)&&(yPos/yPos1 >= 0.999))||(simSpeed != simSpeedPrev)){
				object.setTranslation(xPos, yPos1, zPos);
				levitation = 0;
				if(simSpeed != simSpeedPrev){delayCountUp = 0;}
				}
		}
		
		simSpeedPrev = sim.getCurSimulationSpeed();
	}
}
Posted September 18, 2020· Edited September 18, 2020

I've been working recently with the export data from NoLimits 2, however I'm struggling a little at converting the vector values (That is to say, [FrontX/FrontY/FrontZ][LeftX/LeftY/LeftZ][UpX/UpY/UpZ]) for rotation data into angles, as each value seems to inadvertently affect all of the other values - does anyone know / have any experience with how I could "decode" them?

I don't have much experience with processing exported NL2 data but the front, left and up vectors form a moving frame along the track so maybe
this helps assuming you want to convert to euler angles. Alternatively these vectors can be viewed as the colums of a rotation matrix so euler angle decomposition of rotation matrices might provide another starting point

276 to 300 of 347