Hiding Meshes.
I have kept the roof invisible until now so that you are able to see that the train is stopping as designed. We could restore it by changing a tag in config.txt but doing that wouldn't teach you about the Property Editor or about saving object data to the session.
Trainz doesn't provide any means within the user interface to hide and display meshes but it does provide a mechanism to extend the interface by providing a Property Editor for any scripted object which needs the facility. This needs quite a lot of code and quite a lot of effort to understand but it provides powerful and extensible facilities so it will be well worth the effort.
include "Buildable.gs"
class Tutorial isclass Buildable {
bool doorsOpen = false;
bool roofVisible;
public void Init(void) {
inherited();
SetFXCoronaTexture("corona",null);
AddHandler(me,"Object","","ObjectHandler");
}
Asset GetCorona(string mesh, string effect) {
Soup meshtable = GetAsset().GetConfigSoup().GetNamedSoup("mesh-table");
Soup effects = meshtable.GetNamedSoup(mesh).GetNamedSoup("effects");
KUID kuid = effects.GetNamedSoup(effect).GetNamedTagAsKUID("texture-kuid");
return World.FindAsset(kuid);
}
thread void RingTheBell(void) {
while (doorsOpen) {
Sleep(0.35 + World.Play2DSound(GetAsset(),"bell.wav"));
}
}
void ObjectHandler(Message msg) {
Vehicle vehicle = cast<Vehicle>msg.src;
if (!vehicle) return;
if (msg.minor == "InnerEnter") {
doorsOpen = true;
SetMeshAnimationState("default", true);
SetFXCoronaTexture("corona",GetCorona("default","corona"));
RingTheBell();
}
else if (msg.minor == "InnerLeave") {
doorsOpen = false;
SetMeshAnimationState("default", false);
SetFXCoronaTexture("corona",null);
}
}
/* SetProperties() is another method which is called by the game engine. Its purpose is to
read the session files and to provide you with the opportunity to retrieve any data which
has been saved there in previous runs. The method is also called when the Property Editor
is closed, to save any changes which have been made. The Undo system also uses this method.
We are using it here to restore any value for the roof visibility which has previously been
saved by the game. There will be nothing there of course, when the asset is first placed */
public void SetProperties(Soup soup) {
inherited(soup);
roofVisible = soup.GetNamedTagAsBool ("roof",true);
SetMeshVisible("roof",roofVisible,1.0);
}
/* GetProperties() is again called by the game engine, this time it's used to take any changes
made by the user and to save them to the session files. */
public Soup GetProperties(void) {
Soup soup = inherited();
soup.SetNamedTag("roof",roofVisible);
return soup;
}
/* GetDescriptionHTML() is where you define the HTML code that will be loaded into the Property
Editor when you press [F3] in Surveyor, select the [?] icon, and click on the Engine Shed. The
HTML code supported is very simple. You just need to provide the basics. The local variable
roofStatus is used to provide text to be used by the interface to show whether the roof
is to be hidden or displayed.
<a href=live://property/roof> is a special hyperlink format used by Trainz to identify a link
clicked within the Property Editor. The 'roof' part, known as a propertyID, is used by other
related functions to identify values that the user wants to modify. */
public string GetDescriptionHTML(void) {
string roofStatus = "Show";
if (roofVisible) roofStatus = "Hide";
string html = inherited()
+ "<font size=5><br>"
+ "Roof: <a href=live://property/roof>" + roofStatus + "</a><br>"
+ "</font>";
return html;
}
/* The remaining methods are all standard routines called by the game to establish what needs
to be done in response to a user click on any of the links in the Property Editor.
GetPropertyType() establishes whether the property, "roof" in our case, is to be treated as
a number, as a string value or is to be selected from a list. Roof represents the simplest
property type, where merely clicking on the link is enough information for the game to do what
needs to be done. We indicate this to Trainz by returning the string "link". */
public string GetPropertyType(string pID) {
string result = inherited(pID);
if (pID == "roof") result = "link";
return result;
}
/* LinkPropertyValue() is where we tell the game what is to be done when properties which have been
defined as "link" are pressed. In our case we take the boolean value roofVisible and make it the
opposite of itself, toggling its value. (The symbol ! means not). Having done this we can use
the new value of roofVisible as a parameter to SetMesh() which hides or shows the submesh. The
final parameter of SetMeshVisible() specifies the time to fade the mesh in or out. */
public void LinkPropertyValue(string pID) {
if (pID == "roof") {
roofVisible = !roofVisible;
SetMeshVisible("roof",roofVisible,1.0);
}
else inherited(pID);
}
};
The main thing to notice about these standard methods is the use of the keyword inherited(). Each of the class definitions used in TrainzScript inherits properties from its parent. Buildable, which we are using here, descends from SceneryWithTrack, which descends from MapObject, which descends from MeshObject and so on. inherited(), in its various forms, ensures that anything which the ancestors of the current class have to say about the operation in progress is taken into account.
When the game calls GetDescriptionHTML() the call is first referred to our object's immediate parent. The referral is chained up throughout the hierarchy. At each stage the ancestor object is allowed to add HTML code to be presented in the Property Editor. None of the ancestors actually add anything at present, but they might do in the future. If you miss out the calls to inherited() you might well miss out on any future advice from your grandparents.
Save the script file and commit the asset. You should now have access to a link in the Property Editor enabling you to hide or show the roof mesh. If you show the mesh and save the session, the roof should still be visible when you reload. This is thanks to GetProperties() and SetProperties(). Be aware that properties are not saved to the map, only to the session files. If you load the map without a session you will only ever see the asset's initial defaults.
Next Tutorial: Handling Name Effects.