I've spent a lot of time fiddling with various parts of the game. Trying to find ways around limitations, misappropriating systems, stuff like that!
With the MD specifically I've tested and tried quite a lot of different things. In this post I want to detail some of those tricks and ideas that may or may not be useful to other modders, or at least interesting. Here we go, in no particular order.
==============================================================================================
Typecode Traversing
The MD has no good way to actually get the typename of a ship or other object without knowing that very typename, thus hardcoding it. That is the reason the SRST library (library to tell the MD which ships to use) exists and is so incredibly unwieldy and terrible for compatability (since every mod needs to add its ships to it manually, making combining mods a pain). I wanted to come up with a way to get rid of the need for a huge file like SRST, so I had to come up with a way to go through the TShips within MD and catalogue what was there. Except the MD doesn't really have that ability at all. At least it's not supposed to. There is, for example, no way to get the first entry in the TShips. Or the second. Because MD has no access to its index. And without being able to iterate through the TShips there is no way to catalogue it.
So here comes the trickery. The way the engine differentiates typenames (SS_SH_A_TL for example, the Mammoth) is internally not really by reading the letters but by knowing at which index of the TShips that entry is, which results in every index position being represented by an integer. Thanks to Jack08, I got to know that the Mammoth, the entry at index '0' in the TShips (hence whenever a ship is not found in the TShips, a Mammoth is spawned instead, as it is the default to fall back on), is represented by the number '458752'. The typecode of the Mammoth. And it turns out that number can be used by the MD in this manner:
Code: Select all
{lookup.type.name@458752} ==> "Mammoth"
So. If the Mammoth is at index '0' in the TShips, and thus the first typename listed, thus it follows that
Code: Select all
[ typecode at index '0' ] + 1 == [ typecode at index '1' ]
Similarly, by using '{lookup.type@SS_SH_A_TL}' you'd get its typecode.
So, to sum up, we now have a way to iterate through all entries of the TShips (but theoretically also any other T-file, say, TAsteroids). What we need now is a way to know when we've reached the end of the TShips. Because turns out, if you try:
Code: Select all
{lookup.type.name@ [ last TShips entry ] + 1 }
Anyway. One solution might be to simply define the last ship entry in the TShips and then not iterate any further. But that again requires hardcoding that we want to avoid. I've tested some more and ended up with this, which works:
Code: Select all
<set_value name="CSTL.tempTypecode" exact="(458752+{value@CSTL.typecodeCounter})"/>
<do_choose>
<!-- This means that the end of the TShips has been reached. -->
<do_when value="{lookup.type.class@{value@CSTL.tempTypecode}}" exact="lookup.type.class@{value@CSTL.tempTypecode}">
<set_value name="CSTL.endReached" exact="1"/>
</do_when>
Turns out that when you try to get the class of a typecode that is not a ship, you get the MD code back, hence the check for 'lookup.type.class@{value@CSTL.tempTypecode}'.
Thus we have now found a way to check if we have gone through the entirety of the typenames to cancel the iteration, enabling us to completely automatize SRST.
There is more stuff that is part of replacing SRST but that goes beyond the idea of typecode traversing. It's also not completely finished or tested yet, but if you're interested you can find the current iteration of my SRST replacement, CSTL, here.
Note that it is part of a larger project of mine and hence relies on other files which are not included in this link.
==============================================================================================
Local Variables on Objects
This might not be that new or surprising to anyone that has worked with the MD before but using the engine ID of an object allows the easy setting of local variables.
Essentially, every object in game, that is, every single ship, station, but also "abstract" object like a sector is represented by a number for the engine. The same as for the typecodes for ship entries in the TShips. The way to get that number is very simple. You can get it by simply using '{object@this.yourObject}'. A "local variable" can be set by simply doing:
Code: Select all
<set_value name="{object@this.yourObject}_myValueName" exact="1"/>
Bear in mind that I don't know how exactly Shush's LIFE script works or whether it would have that issue. It just presented itself as a good way to explain a use case.
==============================================================================================
MD Arrays
The MD doesn't have any proper support for arrays. The most it can do is groups of objects, but that's not suitable if you have a number of variables that you want to save in an array. But, hey, we can just make our own after all.
Code: Select all
<set_value name="this.arrayName_1" exact="10"/>
<set_value name="this.arrayName_2" exact="9"/>
<set_value name="this.arrayNameSize" exact="2"/>
Code: Select all
<do_all counter="count" exact="{group.object.count@this.groupOfShipsInDifferentSectors}">
<set_value name="this.sector_{counter@count}" exact="{group.object.{counter@count}.sector@this.groupOfShipsInDifferentSectors}"/>
</do_all>
<set_value name ="this.sectorSize" exact="{group.object.count@this.groupOfShipsInDifferentSectors}"/>
Arrays in "proper" programming languages have several other functionalities though, which the MD obviously doesn't support since we just created those arrays out of normal variables. Thus it can be a bit complicated to implement different operations you'd want to carry out on arrays. So far the only thing I've had to implement for my purposes is a sorting library that allows me to sort the values inside an array. You can find the code for that here but again it's part of my larger project so it might not run on its own. It's a simple implementation of a bubble sort. Also, it's untested ingame but I'll get around to that and the adjustments to its code hopefully fairly soon.
==============================================================================================
Saving Strings
While it's possible to compare the name of an object to a string in a condition, that string in the condition is a constant. It cannot be variable. The only thing you could do is do a check like:
Code: Select all
<check_value value="{object.name@this.myShip}" exact="{9250,1}"/>
So. The MD cannot save a string to a value. Thus, saving strings seems impossible. What it can do though is to change the name of an object. And read it. And the MD can also temporarily create an object where the player will never see it or even realize it exists. Hence, if we want to save a string in MD we can just write it into the object name of a beacon in a random sector 500km out with hidden="1". And we delete it once we don't need that string anymore. Unwieldy, I agree, but it works.
Might seem fairly useless but let's remember this: MD variables work inside of text IDs. Sector names are saved to text IDs. Sector name text IDs can contain MD variables. For example the variable '{object.name@this.myHiddenBeacon}'. And the SE can offer the player a text field to input a string. And the SE can also then set that string as the name of our little object, hence in theory renaming the sector. Poof. Player-named sectors. IF it works. Haven't tested it yet.
In case you want to just generally save a string though, I wrote a small library for that. Once again though. Part of a larger project, yadda, yadda.
==============================================================================================
Picking a Random Value from a Set Group of Values, and not Picking any Value Twice
This is a solution to a very, very specific problem I had and honestly might not be particularly useful to anyone: I wanted to have a group of values from which I want to pick one random value after another but not pick any value twice. There's probably also a better solution to this but the thing I've come up with is to just simply create a group of temporary objects, set their names to the values, then use '{group.object.random@this.myGroupOfTempObjects}' in conjunction with the 'remove_from_group' command until there are no more objects in the group. Not pretty for sure.
==============================================================================================
Variable Choice of Text IDs
I work a lot with variable text and such. Thus, depending on the occasion I want to get one text ID of a set or another. This can easily be achieved by a little bit of t-ID reference magic. This is used in vanilla MD code as well but still a very useful trick.
Code: Select all
<create_ship>
<pilot shipname="{9250,{value@this.value1}0{value@this.value2}"/>
</create_ship>
==============================================================================================
"Outsourcing" Data to Text Files
Another little known about trick is this:
Code: Select all
<set_value name="this.value" list="{9250,1}"/>
Code: Select all
<t id="1">1|2|3</t>
What it also allows is for an easy way for players to adjust values that the MD uses. For example, it would be possible to introduce a global mission reward multiplier that multiplies all mission rewards. By default it is set to '1' - none. But by "outsourcing" that variable value to a text ID, which is easily readable by a normal user, the user can then set that multiplier to '2' or '3' or whatever.
Similarly it would be possible to, for example, set up a MD file for compatibility with a number of major mods. And depending on whether a value in the text ID is set to, say, 'LU' or 'XRM', the internal code would adjust to be compatible to that major mod.
==============================================================================================
I may have more to post here in the future but this'll be it for now.