Handling Name Effects.
(Hint for solving some error issues) |
|||
Line 1: | Line 1: | ||
− | '''''Some issues with the property browser leading here to errors. For hints to slove this see the forum thread [https://forums.auran.com/trainz/showthread.php?172571-Some-trouble-with-string-property-editing&p=1976756#post1976756|Some trouble with string property editing].''''' | + | '''''Some issues with the property browser leading here to errors. For hints to slove this see the forum thread [https://forums.auran.com/trainz/showthread.php?172571-Some-trouble-with-string-property-editing&p=1976756#post1976756|Some trouble with string property editing]. (ek.skirl)''''' |
Latest revision as of 05:08, 5 August 2023
Some issues with the property browser leading here to errors. For hints to slove this see the forum thread trouble with string property editing. (ek.skirl)
Dealing with name effects in the Property Editor is similar in principle to dealing with submeshes except:
- Name effects can't be edited simply by clicking on a link, we need to supply a string editor.
- In order to be editable the name, as supplied to the Property Editor, can never be blank. If it were we would not be able to select it for editing.
- Name effects are rather troublesome because the script call that we need to use, SetFXNameText("effectname",value), will not accept an empty string without causing a script exception.
- To deal with these issues we need to provide additional property handling code and some messing about to avoid seeing our old friend the exception dialogue.
include "Buildable.gs" class Tutorial isclass Buildable { bool doorsOpen = false; bool roofVisible; /* It is legitimate to assign an initial value when a variable is declared. The value can be still altered by other code statements. */ string nameText = "None"; /* We are going to be calling a new method called SetNameText() in our Init() method. The method itself will be defined later on but the script will not compile unless it knows the parameters required by the method when it first finds a reference to it. To get around this we can predefine it in the body of the class. */ void SetNameText(void); public void Init(void) { inherited(); SetFXCoronaTexture("corona",null); SetNameText(); 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")); } } /* This is the actual declaration of SetNameText(). We are going to use this method to work around our little problem with null string parameters to the built-in SetFXNameText() method. Since this hack will be needed several times we have 'centralised' it here. */ void SetNameText(void) { if (nameText == "None" or nameText == "") { SetFXNameText("name"," "); } else { SetFXNameText("name",nameText); } } 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); } } /* Additional code to retrieve saved values of nameText. */ public void SetProperties(Soup soup) { inherited(soup); roofVisible = soup.GetNamedTagAsBool ("roof",true); SetMeshVisible("roof",roofVisible,1.0); nameText = soup.GetNamedTag("name"); SetNameText(); } /* Additional code to save the present value of nameText. */ public Soup GetProperties(void) { Soup soup = inherited(); soup.SetNamedTag("roof",roofVisible); soup.SetNamedTag("name",nameText); return soup; } /* Additional code to present nameText in the Property Editor. */ 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>" + "Name: <a href=live://property/name>" + nameText + "</a><br>" + "</font>"; return html; } /* When we edit nameText Trainz will provide a separate dialogue box that we can type into. This method requests a caption for that dialogue. */ public string GetPropertyName(string pID) { string result = inherited(pID); if (pID == "name") result = "Enter Name Text"; return result; } /* Advise Trainz that the name property is of type "string". */ public string GetPropertyType(string pID) { string result = inherited(pID); if (pID == "roof") result = "link"; else if (pID == "name") result = "string"; return result; } /* GetPropertyValue() enters the current value of nameText into a dialogue to allow it to be edited. */ public string GetPropertyValue(string pID) { string result = inherited(pID); if (pID == "name") result = nameText; return result; } /* SetPropertyValue() takes our edited value and assigns it to our nameText variable. This will only happen if we actually change the value in the TRS dialogue. Otherwise the original value will not be altered. */ public void SetPropertyValue(string pID, string value) { if (pID == "name") { if (value == "") nameText = "None"; else nameText = value; SetNameText(); } else inherited(pID, value); } public void LinkPropertyValue(string pID) { if (pID == "roof") { roofVisible = !roofVisible; SetMeshVisible("roof",roofVisible,1.0); } else inherited(pID); } };
Note that there are no rules about the order in which methods, constants and variables are declared, except that all declarations must be made before they are used by other sections of the code.
Adding new properties to the Property Editor is straightforward enough although because of the way that TRS makes a large number of method calls, each requesting a small piece of information, it can become confusing as your code becomes more complex.
There are further methods for editing lists and numbers and parameters can be added to the specifications returned by GetPropertyType(), specifying maximum and minimum values and the length of strings.
You can test the code in the usual way.
Next Tutorial: Texture Replacement.