Simulator Enhancements

The combat simulator in Starsector is essential to the experience – you need to be able to adjust your ship loadouts effectively, and being able to test out changes quickly is a key part of that. Imagine having to get into a real fight just to see how your new set of weapons performs! That simply wouldn’t do. This means that the simulator was added early on in the development process. This also means that it hasn’t quite kept up with the times, and was very much due for another look.

I wouldn’t say that the simulator is in a bad place – it works, it does the job it’s supposed to do – but there’s also definitely a bunch of smaller issues. For example, the set of ships available to fight against is pretty arbitrary, and for historical reasons, even contains some hand-made “damaged” versions of hulls that you can’t find anywhere else in the game. That could be partially resolved by just cleaning up the list of sim opponents, but with the number of ships in the game, most of them would have to be cut if it were to comfortably fit in the old “one list of ships” UI presentation. For reference, here’s what it looked like, before all the changes in this post:

The simulator also doesn’t give you a lot of flexibility as to the quality and behavior of your opponents. All of the opposing ships are locked to the “steady” personality, baseline-quality ships (without any negative d-mods or positive s-mods), and have no officers. In some ways it’s a positive – it gives you a pretty steady baseline to test against – but it also skews the results. Testing against the baseline sim Onslaught-class battleship is not going to reflect a ship’s performance against a highly aggressive [REDACTED] cruiser piloted by an AI core.

Design goals
Before going further, I think it’s good to step back and establish what we actually want from the simulator – or, in this case, I think it’s helpful to think of it in terms of the opposite, what we don’t want from it. And that is: the simulator should not spoil the rest of the game.

In practical terms, this means that some ships are too “special” to show up as simulator opponents at all, and that others might show up in the simulator, but require being unlocked (i.e. require being encountered in the game in some way) so that their availability in the sim is not a spoiler.

During the design process, I spent a while thinking about the details of how unlocking ships might work, couldn’t come up with answers I felt solid on, and then decided to implement the “full” version of simulator and see how it felt – and once it was that far along, how the unlocking should work became pretty clear. So, in this blog post, we’ll stick with the same flow, and talk about that after laying out how the updated simulator works.

Also – whatever the ship-unlocking mechanics are – the new simulator should not be worse than the old in terms of what’s available, even in its base, nothing-unlocked state. Don’t want to lose the forest for the trees, here; Starsector is not a game about meta-progression, and we’re trying to make the simulator better, not more restrictive.

I also don’t want to make the baseline UI for the simulator more complicated; wouldn’t want a new player to get hit over the head with it and feel overwhelmed when all they’re trying to do is run a quick test of their first ship loadout ever.

A “show advanced options” button in the sim deployment dialog seems to fit the bill here – until that’s toggled on, the new simulator just looks like a cleaned-up version of the old. The game remembers the state of this button (and of the rest of the options that it brings up), across savegames, so that it’s not a hassle for a more experienced player, either. You’d basically need to press this button a total of once, and it opens up a pair of side-panels.

Also, to streamline things a bit and to remove clutter, you can now select multiples of a specific ship to deploy by clicking on it multiple times – it cycles through “deploy x1” to “deploy x9”, and you can right-click to clear the selection. This removes any need to have more than one of the same ship variant in the simulator, and cleans up the list of ships to deploy.

Factions and categories
So, what are the new options? First off, we have ship categories on the left side-panel. The “Default” one has the basic ship set (a cleaned-up version of the current simulation opponents); the rest are categories for factions. For example, if you want to deploy pirate ships to fight against, you can select the “Pirates” category and go to town. The selected category also influences the behavior of the options on the right side-panel, but more on that in a bit.

There’s also a special “Custom” category; you can add whatever variants you like to it, from any of the other categories, if you’d like to have all of the things you personally prefer to use all in one place.

Advanced options
On the right side-panel, we have the options for fine-tuning the quality and behavior of the opposing ships. The options are fairly self-explanatory, so let’s just do a quick rundown.

Aggression
A “default” setting, and the full range of explicit settings from “cautious” to “reckless”. The “default” setting makes the aggression level be governed by the selected faction. For example, if you select “Pirates” and leave the aggression setting on “default”, the opposing ships will have the typical aggressive behavior pirate ships exhibit in the campaign.

Officers
Defaults to “none”. You can also select “some”, which comes into play when deploying multiple ships, and there are options that just put max level (for that faction) officers on all opposing ships. The officer skills will be picked in the appropriate way for the selected faction. If the “Default” category is selected, both officer skills and personality/aggression will be governed by the “independent” faction settings, which are neutral/average, and you have a choice of officer level.

Ship quality
No faction specific settings here, just the full range from “lots of d-mods” (bad) to “lots of s-mods” (good). The default is to have neither; a regular pristine-quality ship.

AI cores
Similar to officers, but only applies to automated ships. The options range from none or some cores to having a fixed type of AI core on every opposing ship. More on this when we talk about how ship unlocking works!

There is also a setting to “integrate” the cores into their ships, increasing their level by 1 and giving them an extra combat skill.

Randomized loadouts
A toggle to make opposing ships have (somewhat) randomized weapons and hullmods.

Group deployment
And, finally, there is an option to quickly select a group of opposing ships to deploy. You choose a target number of deployment points; the composition selected depends on the chosen faction – for example, if it’s the Hegemony, more capital ships will be selected, and so on.

Unlocking mechanics
Now that we’ve covered the full functionality of the new simulator, let’s get back to the unlocking-stuff mechanics. As I mentioned earlier, Starsector is not a meta-progression game, so we’re not looking for anything elaborate here, or that’s a pain for the player, or that the player particularly “works” for. The goal is to generally avoid spoilers and overwhelming a new player while being basically a non-issue for anyone that’s played the game for a while; this unlocking is something you only do once.

With that said, it’s pretty clear that we need to unlock two types of things – the actual ships, of course (or, more precisely: ship variants), but also the factions. There are a lot of “annoying details” here, something that once it’s sorted out just works and you don’t really think about, but is actually kind of a pain to get right, and I’d like to talk about these!

Unlocking factions
First off, for unlocking factions – we don’t want to show empty categories, and don’t want to overwhelm the player with too many of them. And the [REDACTED] faction, we definitely wouldn’t want to just show that to a new player right off the bat; they’re something special you’re meant to discover. (The same logic largely applies to unlocking ships, too.)

So, why not do the obvious thing and just hide the empty categories? Because the same variant might show up in different factions – for example, let’s say the same Hound-class frigate loadout is used by both the Pirates and by some top-secret faction we don’t want to show until it’s been encountered by the player – but if we did the obvious thing, it would show after the player unlocked that ship for the pirates, which would both be a spoiler and a bit confusing.

Alright, so factions have to be unlocked separately from loadouts. Is just encountering a faction fleet in the campaign enough? I’d say not; going back to the [REDACTED], just popping into a high-danger system and having the faction pop up in the simulator would be a bit of a spoiler. Fighting against the faction seems like the cleanest way of doing it – once you’ve done that, having it be available in the list of simulation opponents is by definition less of a spoiler.

Ok, great, now that we’ve settled that, let’s move on to unlocking ships! … except, wait, there are actually a bunch of problems with this approach.

Some fleets in the campaign have one faction be used for selecting the ships that are in the fleet, and are then set to belong to a different faction when they’re actually spawned. Some examples of this:

Bounties! Some of the bounties are “deserters” – e.g., a Hegemony deserter fleet would be using Hegemony ships, but would be assigned to the “pirate” faction.

The Lion’s Guard – an elite subfaction of the Sindrian Diktat – uses a special set of ships, but the fleets are flagged as Sindrian Diktat fleets.

Mercenaries – there is a special “mercenary” faction, used to create elite mercenary fleets, which are then spawned as “independent”, or perhaps belonging to another faction. The “Mercenary” faction would be very nice to unlock in the simulator, but it’s not one that fleets in the campaign *ever* belong to.

Occasionally, other faction-specific fleets will be flagged as independent for in-fiction political reasons, such as Tri-Tachyon “commerce raiders” that use the Tri-Tachyon ships and doctrine but fly the independent flag.

There’s also *another* problem, related to faction unlocking being a meta-mechanic. Let’s say you’re friendly with the Hegemony, but want to unlock their faction/ships in the simulator. You could save the game, fight one of their fleets, get the unlocks, and then reload. The problem isn’t that you can do this to get unlocks – rather, the problem is you can do this, but it kind of feels bad. You can reload the save, but not your recent memory – you’ve still had the experience of attacking a friendly fleet, and it can jar you out of a role-playing mindset. This is fundamentally unsolvable because unlocks are a meta-mechanic that carries across saves, but I think this can be mitigated – and, in fact, the other problems suggest a good approach.

Solution
And that approach is, we need to figure out what the “right” faction is for a fleet; we can’t just look at what faction it currently is for that. It’s possible to try to store which faction was used to create the fleet in a variable somewhere, but that would be a bit of a pain – there are so many ways to create a fleet, and some of those would certainly get missed.

Instead, I wrote some code that matches the ship loadouts in the fleet against the ships used by all of the valid factions that show up in the simulator, weighing the fleet’s nominal faction a bit more – and the highest scoring faction is the one that gets used.

So, those pirate-flagged Hegemony deserters? They unlock the “Hegemony” faction. Lion’s Guard fleets? They unlock the Lion’s Guard faction, despite bearing the Sindrian Diktat flag, and despite the Lion’s Guard being a faction that does not explicitly show up in the game. Likewise for mercenaries and all the other false-flag fleets.

This also helps with the “attack some friendlies then reload” problem. Like I mentioned, I think it’s inherently not 100% solvable – but being able to get the same unlocks by fighting deserters (and in some cases other types of fleets) makes it so you don’t have to do this, if you don’t mind delaying some of the unlocks a bit. And the as unlocks are something you only do once, it’s not a huge problem in the first place – but still, I think having this way around it is nice; you’re not forced to compromise your immersion.

Unlocking ships
This is closely related to how unlocking factions works, and at this it’s pretty clear that you unlock ships (or, rather, specific variants of ships) by destroying them. Design-wise, I thought this through as a whole; it wouldn’t make a lot of sense to think about factions and ships separately. But, I think it’s worth talking about a few approaches that I’d considered and discarded.

One idea was using “learning blueprints” as the trigger for unlocking ships. It makes some in-fiction sense – if you’ve learned how to produce a ship, you might know how to simulate it in combat (though, with how production works – with blueprints being fed into a nanoforge, with the actual process being poorly understood, this isn’t such a given).

But more importantly, it doesn’t make much in-game sense. Right-clicking on a blueprint package to learn how to build a bunch of ships doesn’t mean you the player familiar with those ships, and that’s really the main criteria. There are other problems, too – blueprints are for ships, not for specific ship loadouts (for example, the Luddic Path has a bunch of specialized ship fits, and it wouldn’t feel right to unlock those without encountering them specifically), and also some of the ships we’d like to unlock – e.g. the [REDACTED] – can’t be produced and so don’t have blueprints at all. So, that was a no-go, just an early idea.

Another idea I’d considered briefly is requiring a ship to be destroyed multiple times for the ship to be unlocked in the simulator. This just makes things more complicated, both for the UI (needing to display this progress somewhere) and for the player, and there’s no real upside here – going back to what the goal is, it’s to *not* make this a hassle. This kind of thing might work in game that’s about meta-mechanics, but this isn’t one.

AI cores
And now that we’ve talked all this through, let’s get back to the AI cores simulator setting – the one that lets you assign AI cores to opposing automated ships, and applies to the [REDACTED] faction. Having this faction in the simulator at all is a bit of a spoiler, so I’m making a bit of an exception here – the only AI cores that can be assigned to opposing ships are ones you already have in your possession (in your  cargo, or, if docked at a planet, also in planetside storage). If you have two Alpha Cores? Great, you can face two ships with Alpha Cores at the same time, but no more than that.

This is, of course,, something that does not carry over between saves, but the nice thing is that it creates a dynamic where the more you’ve fought the [REDACTED] (and thus: gained more AI cores), the better you’re able to simulate strong [REDACTED] fleets.

This is both thematically nice and feels like a good balance as far as not having the simulator spoil things. You can’t just simulate a [REDACTED] fleet full of AI cores unless you’ve already faced something similar in-game. Plus, carrying around AI cores is illegal with a number of factions, and might get you in trouble, so that’s an added bonus, as far as I’m concerned!

Settings
With a feature like this – that makes you unlock things that, if you’re an experienced player, you’ve probably experienced – I think it makes sense to add some settings that short-circuit the process. Thus, there are two settings – accessible by editing the config file (so, not an in-game setting): “allStandardShipsAndFactionsUnlockedInSimulator” and “requireAICoresInCargoForSimulator”. Both do what they say; hopefully it’s self-explanatory.

I don’t think these warrant prime real estate on the in-game settings screen – not even close, if we’re being honest – but it’s good to have, just in case.

Modding
Making sure this new system plays nicely with mods was another design goal. First up, the obvious (but perhaps easy to miss, if one is too tunnel-visioned on just making the system work) – it’s possible to unlock modded ships, then re-run the game with the mod disabled. The game should handle this – it shouldn’t crash when it sees a now-invalid hull ID, and it shouldn’t forget that it’s been unlocked, for when it’s run with that mod turned back on. That does (or should, anyway! I tested it) work.

It’s also possible to include/exclude specific factions and ships from being available in the simulator.

The actual code that drives the new simulator options is heavily customizable, too. The specific config settings are provided by plugin code that could be replaced by a mod option. For example, an enterprising modder could add an “install Tachyon Lance in every slot, including small ones” option, or something perhaps more responsible.

Java 17
And, in unrelated news, the next Starsector release will be using Java 17, instead of the currently-used Java 7. What does this mean to you?

  • Improved performance – somewhere around 30% higher frame rate, possibly more depending on the machine
  • A more stable framerate
  • Improved save/load times
  • No need to switch to a newer Java version when running the game with lots of mods

A big thank you to Himemiko for all the help with the upgrade!

(Why not Java 23, you ask? Well, it’s not exactly “out” yet. And Java 17 is the latest version which supports 32-bit systems, which isn’t a huge deal at this point, but is nice nonetheless. Also, Java 21 – the latest available prior to 23 – seems to actually have  somewhat worse performance than 17.)

 

Comment thread here.

 

Tags: , , , , , , , ,

This entry was posted on Wednesday, March 13th, 2024 at 4:10 pm and is filed under Development. You can follow any responses to this entry through the RSS 2.0 feed. Both comments and pings are currently closed.