the Programming Pantheon

in servitude of Koios & Mnemosyne

Subscribe to RSS feed

Sticky post

New website

I won't be updating this web log anymore, instead I've purchased my own domain name! I'll be using Java and Scala to create my own web log engine, to be more precise, I'll be creating a Bliki.
Eventually I'll be moving all the posts here to there. This is the reason why I haven't been frequently updating this web log the past couple of months.

http://the.programmingpantheon.net/

Diamond Bridge Commander - Projectiles

,

One of the most frequent (if not the most) causes of crashes in Bridge Commander are missing projectile files. BC simply can't handle those. One of the problems is that it only occurs when you (or the AI) actually tries to fire a projectile.
I say projectile, because there are two types of projectiles, torpedoes and pulse projectiles, the former is sprite based, the latter (fixed, but stretchable) model based, those are just the projectiles. Then there are torpedo and pulse systems. The difference there is that for torpedoes there are at most 4 projectile types, each with a predefined maximum of "ammo", you define it once, then it is used for all torpedo tubes.
Pulse weapons use a "charge", each time you fire a pulse weapon some of that charge is deducted, but will restore over time. Each pulse weapon is configured individually. Torpedo and Pulse projectiles can be used interchangably, for BC there is no difference between a torpedo script and a pulse script.

So, BC crashes when a projectile module isn't found, or contains an error.
People usually notice it when they are in a battle, so it's kinda annoying when it suddenly happens.
It gets worse, to find out you have to remember all the ships present when the crash occurred. After that, you will have to try out each ship on its own, against another without projectiles, such as asteroids. When you have found the ship, you can be considerd lucky if it's a torpedo, because in that case, you can simply look it up in the hardpoint, where all torpedoes are listed toghether in one neat place. It is the only a question of going by each of them to check if they are present. If it's a pulse weapon, then you have to go by all the pulse weapon hardpoints and check all the mentioned projectiles. It get's worse when the person doing the checking has no background with programming (languages).

So, can we do anything to make this easier? We can indeed. People could send their installs (or just their scripts directory) to me and I go by all of the ships... Hang on, that does not sound like a good idea at all! While it has been (and still is) a really last resort for me to fix a problem, there has to be a better way.

And indeed there is, even if it is slightly ugly, it won't even involve all the modders out there creating ships to check if they have all their projectiles included, it even works on older already released ships (in fact, on all ships). It's a script, auto loading on mod load, 4709 bytes big (with comments). And it monkey patches the projectile "setting" and loading parts. Yes, I monkey patched them, a phrase which originated from the Ruby community, but of which the practise was already present in the Python community. Well, it was slightly frowned upon, since (as it has been in Ruby) it is a maintenance nightmare. But it honestly was my only choice here! The only proper (programmatically speaking) and legel one anyway (for those interested, the other was patching the executable, much more time consuming, harder, complexer and illegal through the EULA, this would be needed since the logic for loading projectiles is in the executable, programmed in C++, and we don't have the source).

So, what did I do? I tracked down all functions/methods involved with projectile configuration (for hardpoints, not the projectiles themselves) and creation of them. Of the first category there are four methods, of the latter there is one function. And I wrote a function that verifies a projectile module, on two criteria no less, first of all, the most important one, does the module exist? If not, print a warning in the console and replace it with a "safe" module. The other criterium is if it contains five specific functions, Create, GetName, GetPowerCost, GetLaunchSpeed and GetLaunchSound, those seem to be the required functions that BC (executable) calls from outside Python. If one of those functions is missing, then we print it in the console and replace it with a "safe" module.

So why did I put the word "safe" in quotation marks? It is honestly meant as sarcastic. The definition of a safe projectile module is one which complies to the aforementioned criteria. What is the biggest thread to this? That someone doesn't install (or include) the safe projectile, I could have gone with the stock Photon torpedo (in way, I have), but some bigger mods remove even that. The second criterium is infact harder to break, since it would mean someone has to actively alter the file to do so, and most people who would want to include the mod in their own mods (to be on the safe side) wouldn't mess with it (others would make sure they have everything included). So what is the only, truely safe projectile module we can create? The module that does the monkey patching itself. If that module isn't present, then the logic couldn't possibly (have) run. So I copied the stock Photon Torpedo functions. One thing that I have done is changed the name of the projectile to "ProjectileSubstitute".

So, with this little script, a user is safe against missing, or broken, projectiles, and BC is stronger for it! So, to go full circle, I plan to create a serie of mods for BC that will all make BC stronger/robuster, in the end, as hard as a diamond! Here by, the DiamondBC mod is born.

And the first out of N (I haven't yet thought of all fixes, could be just this one, could be 2 could be 10 or more) is the module called "Projectiles".

I should mention, there is another peculiar thing in BC, related to torpedoes. It is impossible to have more than four torpedo types, per ship that is. Infact, in stock BC (and early modding) torpedo types for player ships were limited to two in Quick Battle, and three in Singleplayer. The reason for the two in QuickBattle was a little bit of code, that removed the extra torpedo type(s). But it appears that BC is hardcoded to a maximum of four torpedo types, and will crash if you configure a ship to have more. There is a way around this, but it involves doing the job yourself instead of letting BC do it. And in the past, I have created such a mod, part of a Detail Fixing mod (very old, in BC time). And I suppose mostly broken. But it actually worked. And it too contained code that would prevent BC from crashing on missing torpedo scripts (only for the torpedo system). So why does this mod not contain the "fix" for more than four torpedo type? Well, the tool for hardpoints doesn't like more than four torpedoes either, and hardpoints aren't that easily editted for those without experience and if you were to distribute that hardpoint to others without the script then BC would crash for others. Yes, if you don't distribute the script nor the projectiles, then BC will crash as well. But it's easier to distribute the projectiles afterwards than it is to fix a hardpoint afterwards (different mental payload, and people tend to dump it in scripts/ships/ the wrong directory for it). Aside from that, I want the AI to use it as well, so I'm currently reworking the previous script into a FoundationTechnologies plugin, which will automatically use the script for DiamondBC if it's installed. And since it will be a FoundationTechnologies plugin, it would mean that people without the plugin or FTech would simply fall back to the normal torpedo system with a maximum of four torpedoes. But that is for the future and not for now.

I will leave you with the current, beta, version of the script (I need to check all cases, and I need to check the possibility of a missing sound and missing texture) and a screenshot of the console showing that a projectile is missing.



Now released: http://bridgecommander.filefront.com/file/DiamondBC_Projectiles;99219

Maybe Java?

, , , ...

I'm fairly sure you have come across the following situation from time to time:
Does this null value mean "it is null? or "does not exist?"
Of course any other (magic) constant can/will (eventually) have the same result.

The most prominent (and simplest) example of this occurence is the Map interface as found in Java. The contract of java.util.Map<K, V>#get(K):V specifies that "[it] [r]eturns the value to which the specified key is mapped, or {@code null} if this map contains no mapping for the key." Or rather, if containsKey returns false for a particular key, then it returns null for that key. Not much of a problem, wouldn't you not say? I didn't think so either, but there was this nagging feeling that something was off, not entirely right. It felt as if this was wrong. It is one of those to which you say things like "Meh, I won't be bothered by it", or it "doesn't matter", and you would be quite right about it as well. But what if you wanted to do something about this nagging feeling? Regardless if you could (and with this you can, I suppose) live with for the rest of your life.

Ok, let us solve this problem! But what is the problem anyway? Is it that Map returns null when a key isn't present? No, it's related, but it's a more specialized case, for another example, we need to get down to basics, in Java, there are only a handful of types, a set of what are now called the "primitive" types, with just value semantics (meaning no reference), plus the reference (or may I dare say it, pointer) type. Now, save for the reference primitive, none of the other can be value "null". With that, it is unique in that you can say "no value", with the other primitives, say, integers, you have to specify a certain value as "no value", but what if null suddenly becomes a proper, valid, value? How can you then say "no value"? Yeah, I hear you, still not a problem.

A somewhat related problem, at least in Java anyway, NullPointerException. A null pointer check is one of the cheapest operations on the JVM, HotSpot can even optimize null checks away, and, if triggered later on, deoptimize them back in. So what is the harm in checking it? Nothing at all. So null references aren't all that bad, sure, they are the most common bug/problem, but still, it's not the end of the world. But what if you have a function/method, where null is a valid return, that does not have to mean "no value"/"does not exist" and throwing an exception is too heavy or to crude for that particular spot? Perhaps it's in a tight loop of some kind and the entire try/catch/finally structures just pushes it out of the "fast" margin to the "slow" end, and putting the loop in the try clause isn't an option? Then there might be something for you (it works for me), any Haskeller would, most likely, have recognized the Maybe Monad trying to shout out to you by the second paragraph of this log post.

The Maybe Monad, or the Option in Scala, are incredibly simple constructs, they only force you to deal with the possibility that it doesn't return a "value". A bit of code would be nice to see, in Haskel:
data Maybe a = Just a
             | Nothing


Or the Option type in Scala (simplified! I'll get back to that later):
trait Option[A] {}
sealed case class Some[A](val a:A) {}
case object None {}


Of course, this is also possible in Java (I gave it my own special blend, better readability if you would ask me):

interface Maybe<A> {}
final class Some<A> implements Maybe<A> {
    private final A a;
    public Some(final A a) { this.a = a; }
    public A get()         { return a;   }
}
final class None implements Maybe<Object> {}


To declare a function for all of the above 3 snippets are as follows (signatures only) for an integer division function:

integerDivision :: Integer -> Integer -> Maybe Integer

def integerDivision(a:Int, b:Int):Option[Int]

public Maybe<Integer> integerDivision(Integer a, Integer b)


Why division you ask? Well, you can't divide by zero, now can you? And I wanted an example that wasn't making it unnecessary complex, such as taking the square root of a negative number, which has a proper result! Just not easily modelled in languages such as Scala or Java without breaking everything else. But I'm moving away from my chosen subject for this post.

So, what does this gain us? We are now forced to deal with the possibility that it might return None instead of Some value, it would be fine to return null (well, not in the above example, but the point still stands). Why is it better to make it more explicit? I think it's at least better than having a sudden null pointer exception (or in this case a sudden DivisionByZeroException, or was it ArithmaticException?). An instanceof is also less heavy than a full blown try catch around each time you invoke that function.

In a way, this monad is a light-weight exception mechanism, but to say that it exactly is that would not do it justice. For example, in Scala there is this great parser combinator library (warrents its own post another time!), here they use the Option monad/construct to denote the success or failure of a particular parser (and a combination of 2 parsers yields another parser). Here Some defines the success and returns the state of the stream (and Abstract Syntax Tree till that moment), and while None denotes the failure of a parser, it also returns the location of where it went wrong and what was expected (and what was found). Then in the or parser (or any other binary parser of course) it sees None and returns the application of its right hand side (or it returns the application of the left hand side if it returned Some). In Haskell there is also another variant of this, the Either Monad, which has 4 results, Nothing, Left, Right and Both, with similar implications of course. Alas, this post isn't about Monads, still learning about them, but they are incredibly interesting! So be sure to read about them, but perhaps not the burrito tutorial. :S They appear to be unique to everyone and everyone has to discover them for themselves. But this post is about one particular monad, the Maybe Monad. And it's use outside of Haskell.

Even though the instanceof is fast (similar speed as a null check, according to this), it still has the same elegance as that of a null check. In both Haskell and Scala there is fuss about this, since they have Pattern Matching. So, can we improve this? Can we add some Java idioms to this pattern? Well, of course we can. In fact, the Option in Scala has a few. It is iterable, for None it has no elements, for Some it has 1 element, this enables the use of the Option in the various for constructs of Scala. It has a useful getOrElse function, which, for Some returns the value of Some, or the parameter in case of None. Case classes in Scala also feature automatic hashcode, equals and toString generation (and getters and for vars also setters), and more. And yet, the wonders of case classes in Scala are not in the Scope of this post.

A point should be made about usage of this pattern:

Haskell:
integerDivide 10 2 case of
   Just a -> a
   Nothing -> 0


Scala:
integerDivide(10, 2) match {
  case Some(a) => a
  case None => 0
}


Java:
integerDivide(10, 2).getOrElse(0)

Or without the getOrElse:
Maybe<Integer> result = integerDivide(10, 2);
if (result instanceof Some<Integer>) {
    return ((Some<Integer>)result).get();
} else {
    return 0;
}


Now that we have seen a basic implementation of Maybe in Java, let us come full circle with the Map scenario in the beginning and ask ourselves, can we retrofit the Map to return Maybes? Again, the answer is simply, yes. Albeit not as neatly as we might want to. sad For the purpose of this article, let us keep this "small" (yes, I know the track record about the length of the articles up until now, I aim to please ^_^) and only provide a wrapper to any map and that null values in said map are considered to be "values".

First let us define the interface for the MaybeMap:
public interface MaybeMap<K, V> extends Map<K, Maybe<V>> {
    public Maybe<V> putRaw(V value);
    public void putRawAll(Map<K, V> m);
}

public class MaybeMapWrapper<K, V> implements MaybeMap<K, V> {
    private final Map<K, Maybe<V>> map;
    public MaybeMapWrapper(final Map<K, V> m) {
        map = new HashMap<K, Maybe<V>>(m.size());
        putRawAll(m);
    }
    public Maybe<V> putRaw(K key, V value) {
        return map.put(key, new Some<V>(value));
    }
    public void putRawAll(Map<K, V> m) {
        for(Map.Entry<K, V> entry : m.entrySet()) {
            map.put(entry.getKey(), new Some<V>(entry.getValue()));
        }
    }
    public Maybe<V> get(Object key) {
        if (map.containsKey(key)) {
            return map.get(key);
        }
        return new None();
    }
    public Maybe<V> put(K key, Maybe<V> value) {
        if (value == null) {
            value = (Maybe<V>)new None();
        }
        return map.put(key, value);
    }
    // The rest simply delegates to map
}


You remember when I said it wasn't that neat? It's in the get. We need to do a containsKey to see if it's present or not. But looking at it some more, it stands to reason that no value in the internal map can be null, so whenever we get null from the get, we know it means that the key isn't present. Taking this into account we only need to change the get method to this:
    public Maybe<V> get(Object key) {
        Maybe<V> v = map.get(key);
        if (v == null) {
            return new None();
        }
        return v;
    }


I do admit, I did cheat a bit here, I had not originally thought of the modified put method which replaces null values with Nones. Without it, we couldn't assume that null only means "not present" in the get method.

Even without that, it's not entirely neat, the raw versions of put and putAll are needed here because generic arguments are erased after compilation. Meaning suddenly there would be 2 put methods and 2 putAll methods, but having the same signatures.
The definition of a Maybe<V> put(K key, Maybe<V> value); in the Maybe interface would help for the put (after erasure: put(Object, Maybe) and put(Object, Object)), but not for the putAll (still putAll(Map) and putAll(Map)). Even if we were to overload the putAll for MaybeMap it might still go to the putAll(Map), since MaybeMap is a Map. We could introduce an extra parameter, an enum which defines if null values should be treated as None or not (for example). But this might be something for another post. As it stands now, it is already fairly usable. But let us focus on the Maybe interface and the implementing classes and see what we can do to improve things a bit further.

instanceof is fast, considered to be as fast as a nullcheck, but I suppose an invokeinterface is also incredibly fast, meaning, if we create an isSome (or isNone, doesn't really matter) that is specialized in the Some and None classes, then it could practically be inlined in the generated assembly. And if we do the same for getOrElse, it is the same thing.

So let us do that:
public interface Maybe<A> {
    public boolean isNone();
    public <E extends A> A getOrElse(final E otherwise);
}
public class Some<A> implements Maybe<A> {
    private final A a;
    public Some(final A a)  { this.a = a;   }
    public boolean isNone() { return false; }
    public <E extends A> A getOrElse(final E otherwise) { return a; }
    public A get() { return a; }
}
public class None implements Maybe<Object> {
    public boolean isNone() { return true; }
    public <E extends Object> E getOrElse(final E otherwise) { return otherwise; }
}


But we can do one better; invokevirtual is faster than invokeinterface, and the JVM likes final methods/fields, etc, etc, meaning it can inline stuff. Next, having more than just Some and None as subclasses doesn't add anything (in this case anyway), so we will not allow it.

public abstract class Maybe<A> {
    Maybe(){}
    public abstract boolean isNone();
    public <E extends A> getOrElse(final E otherwise)	{	return a;	}
}


As a side note, we could just have implemented it here, but as mentioned above, it make just as much sense to specialize it all.

public final class Some<A> extends Maybe<A> {
    private final A a;
    public Some(final A a) { this.a = a; }
    @Override public final boolean isNone() { return false; }
    @Override public final <E extends A> A getOrElse(final E otherwise) { return a; }
    public final A get() { return a; }
}

public final class None	extends Maybe<Object> {
    private None() {}
    @Override public final boolean isNone() { return true; }
    @Override public final <E extends Object> E getOrElse(final E otherwise) { return otherwise; }

    public static final None none = new None();
    public static final <E> Maybe<E> getNone() { return (Maybe<E>)none; }
}


That is all there is to it! Seems just another little class that everyone keeps writing because it's easier than just including yet another jar, doesn't it? Just as easy as that Pair (or Tuple) class you just wrote (ok, I keep writing them, surely I am just another average programmer).
Or is it? I should probably explain why I return an E instead of an A with the getOrElse in the None class, well, it is something called "covariance", this has existed since, practically forever I suppose (in Java), it simply means that a subclass may specialize the return type of a method when it overrides said method. In this case, we specialize with E (since it's a subclass of Object). Then there is the issue with not adding a type parameter to None and subclassing directly from Maybe, generics in Java work through a method (to ensure backwards compatibility) called " type erasure" which means that (most) generic type information is lost on compilation. Which means that a List<String> could be equivalent to a List<Integer>, at runtime. So we provide a getter method that simply casts an instance of None to the right Maybe<?> type. This trick is used in the Collections utility class, where it is used for the empty<CollectionType> functions, they store singleton instances for each type, properly specialized for their function and simply return that, type erasure ensures that they have the right type. On the same note, let us add another method that creates Somes. And move them to the Maybe abstract class, seems a little better place for it. This does mean changing the private constructor of the None class to package private. But that isn't such a big deal, it is still private as far as the API is concerned. These helper methods on the Maybe class is also part of the reason for having a base class and not an interface. There are just a few remaining questions for the final api. For instance, should the new some function in Maybe return None on null? It's an interesting question which I can't really give you an answer to. Even if it is because I haven't really made my mind up yet. Null can be a valid value, so it "should" be possible to create a Some with as value null. Perphaps the some function will return None on null, but you can still do new Some(null) and do it that way. But why is this null value keep popping up? And keep being "annoying"? Bugging me about some "code smell" that I can't really put my finger to? What is so unique about null? So different? You can assign it to every reference value. That little fact, I think that might be it for me. It subverts the type system. That would be reason enough for me. While I was writing this post (yeah, other stuff keeps popping up) the very interesting Ola Bini made a post about something called "Bottom Types". I do recommend you to read it, it even mentions the Maybe Monad and null values! I find it uncanny. Well, his post is the better one, that is for sure. p It also mentions an origin of the null reference exception, a Sir Tony Hoare calls it the "Million Dollar Mistake". And yes, this person is an authority on the subject. As an interesting bit on the side, C++ has null pointers, but never null references, and references are "managed", but not in a Garbage Collection kind of way, and has had it for quite a while. The null reference really is an error born of Sloth (laziness). While otherwise a (when properly managed) perfectly good and handy trait among programmers it does seem to have given us a quite a few problems down the line since he invented them 44 years ago, and we are still having this problem, even with the Elvis operators coming in Java7, as the Groovy people call them (among other people). And on that note, I think a little recap of what we have done here is in order before I publish this post, and yes, I shall be coming back to this subject in a future post. Especially after I learn more about Type Systems (currently I only "know" them intuitively, nothing concrete, no names or anything like that, just the 4 basic names and the term "type inference"). Sometimes (always?) it is better to be explicit than to use a magic, possibly having double meanings, constant, such as null. Do tell me, you don't also type in the same String literal time and again in the same function? Surely extract all those literals into one final static field? Or even better, switch to enums! So why not for null? Well, null is compile checked, meaning you can't accidently misspell it. And we have seen (thanks to Ola Bini) that null actually subverts the type system! So how can we make this better? Haskell and Scala show us the way, the Maybe Monad. It is a small collection of three classes that are practically as easy to write as a Pair or (simple) Tuple class. Which everyone always seem to write. It allows us to be explicit when a function returns something or does not return something, without being as "heavy" as an exception while still sufficently distinctive and "present" that you have to deal with it, instead of waiting for a nullpointerexception during runtime. Of course, you can be explicit with null, but it is so easy (too easy) to just "ignore" it, even if the JavaDoc explicity states that you need to deal with null. We also retrofitted a map to return Maybe instances, meaning Some if there is a key and None if there isn't, instead of null for either if the value is present and it happens to be null or if it isn't present. And lastly, a code listing of the Maybe class I had written up for this post, you should put it in some utility package:
public abstract class Maybe<T> extends Iterable<T> {
    Maybe() {}
    public abstract <E extends T> T getOrElse(E otherwise);
    public abstract boolean isSome();
    public abstract boolean isNone();
    public abstract int hashCode();
    public abstract boolean equals(Object o);
    public abstract String toString();

    public static <T> Maybe<T> some(T t) {
        if (t == null) {
            return <T>none();
        }
        return new Some<T>(t);
    }
    private static final None _none = new None();
    @SuppressWarnings("unchecked")
    public static <T> Maybe<T> none() {
        return _none;
    }
}

public final class Some<T> extends Maybe<T> {
    private final T some;
    public Some(T t) { some = t; }
    @Override public final <E extends T> T getOrElse(E otherwise) { return some; }
    @Override public final boolean isSome() { return true;  }
    @Override public final boolean isNone() { return false; }
    @Override public final int hashCode() {
        if (some == null) {
            return 0;
        }
        return some.hashCode();
    }
    @Override public final boolean equals(Object o) {
        if (o instanceof Some) {
            if (some == null) {
                return o == null;
            }
            return some.equals(((Some) o).some);
        }
        return false;
    }
    @Override public final String toString() {
        if (some == null) {
            return "Some(null)";
        }
        return new StringBuffer("Some(").append(some.toString).append(')');
    }
    @Override public final Iterator<T> iterator() {
        return Collections.singletonSet(some).iterator();
    }
}

public final class None extends Maybe<Object> {
    None() {}
    @Override public final <E extends T> E getOrElse(E otherwise) { return otherwise; }
    @Override public final boolean isSome() { return false;  }
    @Override public final boolean isNone() { return true; }
    @Override public final int hashCode() {
        return None.class.hashCode();
    }
    @Override public final boolean equals(Object o) {
        return o instanceof None;
    }
    @Override public final String toString() {
        return "None";
    }
    @Override public final Iterator<Object> iterator() {
        return Collections.emptySet().iterator();
    }
}
PS. Fixed the code to implement the Iterable interface, I shouldn't write this at night.

Now a really (truely) small post, a tiny remark about a tiny bit of language...

, ,

Yeah, the title is longer than the real post.

The English can say a sequence that the Dutch can't. Atleast not without proper care and precautions.
Wait for it, this is a shocker!

The English can say the sequence of two numbers, nine followed by ten.

The entire half of the people reading this (from two, including myself) will go "so what exactly?"
Well, if someone were to say that exact sequence in Dutch, ie. "negen" followed by "tien", then they would say nineteen (negentien).

Just tought that could be interesting, mostlikely known by everyone but me. bigsmile

Now, it should be said, this only happens (in Dutch) in the range of <15,19> (that's a closed, inclusive range, if I remember correctly). After that we get "correct" and say the most significant part before the least significant part, so twenty-one. Instead of this strange and counter intuitive (atleast, now it is for me) nine-ten.

Thinking a bit more about it, the English language has already started sorting this out, atleast it is further along the path than Dutch, since English has changed the most significant part, while Dutch hasn't, yet.

A small (ok, not so small) history of Modding in Bridge Commander, Part 1

Before I begin I should mention that while I've been "here" (in the BC scene) for longer than half it's lifetime, I haven't been here since the real early days, before mods. Foundation was already released, and the first Bridge mods were already in progress. So the early stuff is a bit incomplete at times, my appologies for that. And I also appologize if I mention my own mods a lot, I can be quite proud about them, and yes, that's a character flaw of mine. It should also be noted that I will mention scripting mods for the most part (this is a programming log afteral), I can't keep up with all the mods being released, not even all scripting mods! So I'll focus on the, to me anyway, most important ones. I hope you will not be insulted if your mod isn't mentioned.

Star Trek: Bridge Commander is a game from late Februari 2002 by Totally Games and published by Activision. It's also known as just Bridge Commander and is often abrevated to just "BC". It's set, as the name suggests, in the Star Trek universe, somewhere between the events of Star Trek: First Contact and Star Trek: Nemesis.

What made this game great at first was that it combined elements of Star Fleet Academy (bridge view and crew interaction) and Klingon Academy (third person ship interaction), you can chose to allow the crew to do things (AI) or take the helm yourself. Other things that also made it a succes was the fact that it was one of the first games to use more than a 1000 (I believe the average is 2500) polygons, per ship. At the time this was unheard of. It also ran at acceptable, playable, speeds on a Voodoo 2 card.

The game's life was greately expanded when people found out you could modify the game. Just some terminology, people creating modifications are called "modders", the modifications themself are called "mods" (short for modicafication, singular is mod), "stock" is the word for the original state of an asset in BC that was included with the CD.

First it was discovered that the textures were in the TGA image format. This resulted in simple retextures of the models used, for example, a black Sovereign, but also retextures that improved on the stock textures. It was also quite soon discovered that there were "scripts" in the form of Python modules, but they were all in pyc format, and a decompiler wasn't avaidable.
But quite soon after the European release in early March of 2002 Totally Games released a Software Development Kit (SDK for short) for BC. In it were tools, a "NIF" exporter (NIF is the model format) for 3DS MAX R3, the Model Property Editor (MPE) to create "hardpoints" (which define the statistics for a ship, such as where the phasers are, how strong the shields are, etc, etc), an AI tool, documentation for some of the things, and, most importantly (for me anyway) all the Python files, in their .py, uncompiled, form, ready for us to read and learn.

With the scripts, we learned that things like ships, projectiles, (star) systems were just scripts, just programming, no special syntax or anything, just Python code which followed some predefined interfaces (not Java like interfaces, more API/framework interfaces). Together with the existing stock ships and the NIF exporter people went to work to create their own ships. This let to some experimentation, but some problems were found with the stock way of doing things. For example, all ship references were hardcoded. So the Single Player wasn't easily changed. There is also the Quick Battle (QB) where you can setup simple matches between ships, it uses a simple menu structure of "species->ships". But this menu was also hardcoded, order and all. The main use-case for new ships was with this QB, so for each ship you wanted to add, you had to alter the QuickBattle script. This situation wasn't sustainable, since not everyone had enough experience with scripts/programming (yes, Python is a full blown Turing Complete language). And most people using mods are looking for convenience. So, some people included their modding QuickBattle as well, but you only need 2 mods that do this to get into problems.
There is also another problem, every ship in BC has a number, that is the "species" number (different from the species mentioned above, every type of ship is it's own species, even every type of projectile, but that's a whole other section (Multiplayer, yes, the ship species number is also used in multiplayer). In this case, it made sure the right icon was assigned to the ship for the interface (this was a common problem in those days).

To solve these problems a fellow named "Dasher42" (also of Homeworld fame with the mods Favour The Bold and Sacrifice of the Angles) created a Dynamic Ship Plugin (name unsure, it's old, and it was superceded before I even got BC, I only know of it because 2 persons came across it on 2 days with atleast a year across). With this system a person could write a plugin in a directory called scripts/Custom/Ships (the entire Custom directory was originally meant for extra missions, for example addons by Totally Games), and then you could add a single line to a file in that same directory, to "import" the ship into the game. These ShipPlugin files would then execute and ShipDef objects are created, one for each ship.
With this system, a person called "NanoByte" create a tool that could both create these ship plugin files from stock-like scripts, and it could update the import file as well. NanoByte eventually also created a "BCMod" format, a simple file that concatenated several files and could overwrite the files in your BC installation, it contained a bug where empty files were omitted, this caused a wave of problems with one of his major mods later on.
Even this system didn't entirely feel complete, since you still had to manually change files. This changed with the advent of one of the first "big" mods, QuickBattleReplacement.

QuickBattleReplacement (QBR) is a mod by a person called Banbury, it's intent is to, as the name suggests, be a replacement for the stock QB, it too was setup as a Mission (QB is just a mission with GUI), it just allowed more things to be done with it. Just a couple of examples, you could set the exact location of a ship, you could have more than 1 system to travel to (QB was, originally, limited to 1 system, in a way this still is, except that you can change a file to load more systems when you start QB), you could even have a neutral set of ships, instead of the stock Friendly/Enemy split. But one thing changed it, it could save a setup, and then later load it as well, this code dynamically loaded a set of files. I think the code was originally based on a section in the mainmenu, where it loads custom missions, or that Banbury already knew Python. It doesn't really matter I suppose, he created a small snippit of code that you could point to a directory, and it would attempt to load every module in it. This, combined with the advent of Bridge modding (I did mention the interaction with the crew? That too happens in full 3D), created a small revolution. Dasher42 incorporated the "load every file" snippit into a more advanced plugin framework for BC, which he called "Foundation".

Before we get to Foundation, there are 2 other mods Banbury made, together with Dasher on some aspects of it, before Foundation. They should be noted, not because of their popularity (which is somewhat of a mixed bag, loved by those that know, and have managed to run it, unknown to others), but because they started something.

They added completely new features to BC.

The mods were Shuttle Launching and Secondary Targetting. I have to admit, Starbases (AI-only "ships") could already target multiple ships and in the SinglePlayer there are shuttles being launched, but as far as I could determine, Banbury didn't look at the stock scripts. But still, this was new for the user. The Shuttle launching capabilities, which used the "load each module from a package" snippit, could be added to any ship, complete with configurable launchers for each shuttle, and the number of shuttles used. And could be launched through the Science menu (the distribution of tasks is a bit different from what is seen onscreen, Science is more like Ops here). One interesting ommision was retrieval of the Shuttles, which was added later as another mod by the scripter Defiant (post Foundation).

The second mod, Secondary Targetting, exploited the fact that while a ship instance has a target, it's weapons could be redirected to any other number of targets. It isn't well known these days, because it was hard to get it working correctly, and to use it in the first place. Because it exploited the above fact, it also meant that the camera would always point to the ship you were targetting, not the ship(s) the weapons were targetting. It also used buttons, instead of mosue clicks to target more enemies, and if memory serves me right, you also had to unselect an enemy before you could use that "slot" (10 slots maximum) again. But at the time, it was massive! It was this (type of) technique that someone else (called Sneaker, we shall meet him later on) used for another mod, Inaccurate Phasers. But this is, again, a post Foundation mod.

But then, the Prophecy unfolded, Foundation is born and unleashed to the world, no more changing stock files!

Hark! Hear those Angels sing!

It is this Foundation that is now the basis for all new mods, and it has been since early 2003 (and before?).
Aside for Ships and Bridges, Foundation also provides a couple of other functionalities. For example, "mutators", a way to turn any element included in Foundation (except other mutators) on or off. This, incidently, also was the first MainMenu mod. It also provided "Overrides", Python is a very open language, it allows you to change nearly everything, I even believe (tough can't find it right now) that the Python documentation read "Nothing is Sacred!" In short, this allowed Foundation to reach into a piece of code (modules), and replace functions and values (In Python, there isn't much different from the two). Aside from overides, Sounds, Systems (Maps) and TGLs were added as mutable resources, similar to ships and bridges. Some are more succesfull than others, sounds are very easy to create, just the "name" (to use internally), the file to play, the (optional) volume and (optional) the mutator to use, and others are just harder to do, such as Systems, one is now unused, TGLs, this is (mostlikely) because BC loads a couple of libraries from hardcoded locations, somewhere around last year (written early 2009) I wrote a small Python library that could write (and read) TGL files. I should mention that TGL stands for Totally Games Localization file, and provide a binding from keys to text and audio, so E1M1IntroLuiLine1 would be a key to the text (for example) "Congratulations on your promotion Captain". But by simply replacing this text you could get German (or French) game. At any rate, a lot of these files were loaded through hardcoded paths, and the Python in BC (version 1.5.2) has been modified, for example, we aren't allowed to read or write outside of scripts/Custom/ not even a listing is allowed, or loading modules from outside scripts/, altough are ways around the listing part (through the Load/Save dialog and programmatic access to the internal GUI structure). So I couldn't even replace the original TGLs with my new (and overridable) TGLs that were autogenerated for use. But I'm getting ahead of myself. Foundation was born! And the dawn of a new era in BC modding! (Yes, we do speak of a pre and post Foundation era in BC modding)

It seems pretty neat, doesn't it? The one modification that shall be the one on which all other mods are build, the one file change to end all file changes. It is 42. And yet, not all is quiet, but that is for another installment.

It is the time of Post Foundation.

Considering this article has grown rather long, I'm going split it here. It seems like a neat place to stop. Being a turning point in BC modding. I do appologize if the text has a rather abrupt ending because of it. You better come back for the next installment. wink
Also to come in later logposts, I shall be looking at some of the mods mentioned here and look at the details that made those mods briliant.


See you next time,
--MLeo

So what is this about then?

This weblog is programming, its languages, its structures, its thought processes/transformations. So it might actually be more of a Proglog (Prolog anyone?), I don't particularly like the word "blog", it's a strange contraction from website and logbook to weblog to blog. See what happend? The "we" got cut off, if it were the web, then it would have made slighly more sense, anyway, I'm already derailing, and it's my first post!

Other things I shall also be talking about are languages. Not just programming languages, well, mostly programming languages, but also what I like to call "spoken" languages, even if a language is "dead" (think Latin/Ancient Greek) I would still call it a "spoken" language, because I would be unable to learn it.
I think that statement needs some clarification, I have managed to learn 2 spoken languages, Dutch (native tongue) and English (I try to use UK English, so colour and not color). But I'm not particularly able in those 2 either (one of the reasons I'm starting to write here). Other languages I haven't even been able to learn.

Not any other language? Well, there are these languages called "Programming Languages", those I can learn, quite well if you'd ask me. And no, Lojban is classified, for me, as a spoken language, since I haven't been able to learn that either, even if it's a logical language.

So, what else to write about?
I use the word write here, because I don't like to speak (ok, hate it). This, too, has a reason, I have a stammer/stutter (what is the word anyway?), I've had that pretty much my entire life (I don't tend to remember the early parts of my life, so it's possible that I once spoke fluently, doubt it p).
I also don't quite like things like religion, if I had to, I would describe myself as an "Atheist", but I'm unsure if that's quite right. To put it differently, I don't need an explanation for everything. I most certainly don't need a (bogus) placeholder for it, and even worse, I don't need to get upset if some "belief" gets invalidated. I won't care what you belief, I also won't discriminate you for it, just as long as you don't over actively try to convert me, or harm me.

Now, some of you might point out to me at the subtitle of this log. "In servitude of Koios and Mnemosyne".
Those are two Titans of the Ancient Greek mythology (but you already knew that, right?).
So what is this about no religion? Titans were even considerd a form of Devils back then!

Well, at the top I mentioned that this log will be about programming, I should probably say it's more about Software Engineering than just the act of programming. Now, in both you need to solve problems. And what do you need for that? Intelligence. And what else? (There is more?) Memory.
And of course you knew already that Koios is the Titan of Intelligence and that Mnemosyne is the Titanes of Memory. These two aspects are at the core of programming, because without memory you wouldn't be able to remember what worked and what didn't work, you would need to be incredibly intelligent to deduce the right answer upfront, or infact, multiple times since you can't remember previous versions of what didn't entirely work right. Mostly because it's stateless, it doesn't tend to remember other invocations. And didn't the proverb go something like "Those who don't learn from history repeat the same mistakes?" In other words we need Memory.

But why can't you not go with Memory entirely? Unlike intelligence, it's statefull. Well, for this we invoke the proverbial "An infinite number of monkeys on an infinite number of typewriters with an infinite number of paper and an infinite number of lint, will eventually produce Shakespeare's DNA in some ancient Klingon dialect" (I think it has more chance to be in that form than, say, Hamlet).
In, hopefully, some less words, just memory will only get you a little, since it would take quite a long time to eventually get what you want since you are brute forcing it the entire way.

So a balance of the two would be quite nice.

What else? Oh yeah, books. I'll also be talking a bit about books, perhaps not a lot, mostly programming languages I suppose. But whenever I get (and read) a new Pratchett book I'll mention this.

And something I'll mostlikely talk least about, real life. There are some things I come across I'll just have to write about, something that has riled me up so much I can't ignore it. I don't like to get emotional over things, it seems to impare proper thinking. Iritation/anger for the worst offenders, even if I can then speak fluently, I don't like to be in that state all the time. One odd thing, whenever I have spoken (and it went a bit hard) I tend to forget what I just said, and it impares the thinking process. Quite annoying, especially with telephone conversations, I still need to figure out how to record telephone conversations, or I'll forget them (quite soon after the end).

And we're still not done!

A bit more about myself to wrap this introduction post up, I like quite a lot of other things, in no particular order, Discworld, Star (Trek|Wars), Lord of the Rings (all 5 generally known collected volumes), British Detectives (Inspector Morse, Touch of Frost, Midsomer Murders, Silent Witness, but not US detectives like CSI: .*, etc, etc. Oh, and Doctor Who, I quite like Doctor Who, and I'm crackers about Wallace and Gromit (find the reference), Monty Python tends also to be fun. Oh, and QI, don't forget QI! I also like Stephen Fry's (the host of QI) works, TV and written.

Currently I'm a part-time student/software engineer. I study Computer Science & Engineering on TU/e in the Netherlands, and I work for ISAAC, who also fund my study. I already have a Bachelor degree on the same subject from a diffrent school in the Netherlands, for which I took 2 internships at ISAAC, which we both enjoyed.

ISAAC is a Java "shop", where we create "made to fit" software, mostly in Java.
I quite like the JVM platform (especially HotSpot), so most of the time I'll be looking at languages that run on it, so Scala, JRuby, Clojure. But I won't limit myself to that, I also quite like Haskell and Lisp/Scheme. And C++ can also be fun (Template Meta Programming for example, I would like to thank Andrei Alexandrescu for his book Modern C++ Design that made my really appreciate it).

That's it for now, I'll be customizing this log for a while, then I'll start posting!
I haven't decided on any type of schedule or content length, since university is taking quite some time.

Ok, that's really it for now. wink
See you (who-ever is reading anyway) around, and till my next post.

--MLeo

PS.

I'll also be talking about the projects I do in my spare time.
February 2012
S M T W T F S
January 2012March 2012
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29