July '20 Update

Published August 02, 2020
Advertisement

Well, summer's in full swing here in Maryland. I've managed to keep myself quite busy with my project making some very good progress. The overall length of this update can probably be seen as proportional to how engaged I was with the work I put in this month.

Recap

The goals for July were as follows:

  • Mission Timers and Duration - Make the missions (at least the non-narrative ones) able to expire after a certain amount of time passes. Also make going on missions able to pass a certain/random amount of time by going on them. The idea being to introduce some tension between the choices of missions and other tactical choices.
  • Introduce a strategy mechanism to balance out the persistent damage introduced last sprint. So I'll introduce a new project that can restore the status of starships that have been damaged in combat.
  • A new UI for the end of missions that can show various bits of result data, like the loot table rewards and the new status of any starships involved in combat (or at the very least the ships brought by the player).

Results

I think I did really good! Everything when along pretty well and was even able to get to things that I thought I would have to push off to this sprint.

Mission Timers

Not a lot to say here, other than Done! In this image you can see the Tactical Deployment screen and for each mission it lists 1) how long it's available for (in days): A and 2) it's duration, or how many days will be passed by deploying on that mission: D. It's obviously not an ideal UI, but it's sufficient for now. Eventually this information (or at least the Availability) should also be available on the Navigation screen, but it's not there yet.

Current status of the Tactical Deployment screen

Ship Repairs

This was the most complicated bit that I needed to make because it involved quite a few extensions to the transaction system and a few of it's adjacent components. Being able to do things like query an input param to determine what possible inputs are legal weren't supported. I also needed to be able to group and bind transactions with some/all it's inputs into an option that could be remembered and attached to a UI element (a button really).

Here's the repair screen. It mostly reuses the transaction screen tech that is used by the marketplace and construction screens. The new bits are 1) input expansion and 2) text injection. For the repairs, it wasn't really going to be feasible to have multiple transactions since the ship instances are completely dynamic. So I needed to be able to create a single transaction that could be given the starship it was supposed to repair. This was easy enough, I just needed to make a new input param type that required a starship. Next I needed to be able to query that param for all the valid inputs. Then I can use those possibilities to create options that are groups versions of a transaction and some predefined inputs. It's sort of like std::bind or lambda captures. What you can notice is that there are only 4 ships listed, whereas the game (currently) starts you off with 8, so it's only creating repair options for the ships that actually need repairing. Currently the duration is just a default value that needs some additional work. The other interesting bit here is the transaction name. With only one transaction, the actual asset data couldn't possibly have a name that is useful in a context like this. So instead the name of the project is actually “Repair {Starship:Name}” and I use a process of text injection to insert runtime string data into the string before displaying it. See the Bonus section for more details.

Next is the dialog that comes up after clicking on one of the options in the repair screen. In addition to being able to select the ship, I wanted the player to be able to select the degree to which they wanted to improve the condition of the ship. Again it was a fairly simple thing to create a new input parameter type for the transaction and have it be able to provide all the valid options. At first I did both parameter expansions on that first screen so that there would have been multiple versions of "Repair USS Enterprise" buttons. I would have had to add to the display name the degree to which it should be repaired, but that wouldn't have been hard. However I decided that it fundamentally wasn't a good idea and it was better for that first screen to have a unique set of options available to the player that they would be able to refine in this dialog. It also leaves the door open in the future for the repair transaction to have additional configurable inputs like the repair status. The biggest missing data here is the costs, both in resources and duration. I felt it was better to ignore those for now and wait until I could do a more permanent solution that involved having to move the construction costs around (see August Goals). In theory the Confirm button becomes disabled if the costs for the selected repair options aren't available.

Here you can see the transaction having been added to the project queue. You can also see the actual name of the transaction because that widget is using the project name directly and not doing the text injection process. This is probably my top thing to fix for August.

End of Tactical

As a reminder, this is what the dialog looked like at the end of tactical at the start of the sprint:

The old Mission Victory dialog

And this is what it looks like now. The first part of the dialog shows all the starships you brought on the mission and what their current damage status is. This is the status I worked on last sprint and is the part of damage that carries over back into strategy. This information is shown whether you win the mission or not.

“Page” 1 of the Mission Complete dialog

In the case of a win, clicking continue will bring you to the rewards which will show you what you got and where you got it from. In this case, there are rewards from completing the mission as well as rewards from destroying the asteroid.

“Page” 2 of the Mission Victory dialog

Bonus

One piece of bonus work I completed was the transaction dialog that was used for the second step of repairing. I hadn't really planned on it when I started the month and once I decided I'd need it I initially added it to my backlog for the next sprint. Ultimately I was able to get to it and I think I've already described it enough above.

The other major bonus piece that I did was the text injection, which I just briefly touched on above. Other people or projects might call it something different, but ultimately it's just a mechanism to get runtime values into a string. UE4 has some pretty robust facilities for text formatting, in fact the ship names are built using it to build up the actual name using a prefix string ("USS") and a unique string ("Enterprise"). However those two elements are themselves just data being formatted together. In this case I have a string like “Repair {Starship:Name}". UE4 has a built in capacity to replace “{ }” blocks with other strings, but I don't have another string readily available. What I do have is the transaction and the data that has been bound to it in the option. So here's how it works in general:

  1. The text injection process takes some input text, a thing that knows how to convert/resolve the groups and contextual data that might be used to create replacement text.
  2. Using a regex (another tool from UE4's bag of tricks), take the input text and create a mapping of strings (like "Starship:Name") to text. (For those not in the UE4 know, strings are just strings, whereas text is specifically localized strings. Generally you don't want to display strings you want to display text.) We assume for the purposes of the regex that it's the things inside “{ }" that we want to replace.
  3. The mapping and contextual data is then passed to the resolver object that was passed in. It can do whatever it deems appropriate to fill in the map values.
    1. If this mapping comes up empty (ie there are no tags that need to be replaced), we can just return the input text directly. A trivial optimization that there's no reason not to make.
  4. Any map elements that haven't been filled in are then replaced with the tag in “[ ]”, so “{Starship:Name}” becomes “[Starship:Name]". This may seem kinda silly, but it makes it a lot more apparent when looking at the UI the difference between a failure in the text injection process vs directly rendering a string that should have the text injection process run on it.
  5. Then we just leverage the UE4 text formatting to replace all the “{ }” blocks with the text values from the map. This is the main reason to use “{ }” as the grouping, it makes it real easy to get the engine to do the replacement work.

That's pretty simple right? So here's how it works a little more in detail for this specific case:

  1. In this case the input text is the name of the transaction “Repair {Starship:Name}”. The resolver is the transaction itself and the context data is all the bound context data that is part of the option that was built for the screen.
  2. The map gets built, but it's pretty simple with one key of “Starship:Name” to and empty text instance.
  3. The transaction (currently) doesn't have any keys it knows how to directly replace, so it just delegates to each of its input and output parameter objects with the map and the context data.
  4. One of the input parameters of the repair transaction, Input_Starship, knows that it can do some replacements if there is starship data included in the context. For this example we'll assume there is.
  5. Input_Starship delegates to the starship data, but includes some additional information of a scope that says “here's something that you should pre-pend to the tags you care about”. This step is meant to allow multiple of the same resolver type to fill in similar tags. Say “{Repairer:Name}” vs “{Repairee:Name}”.
    1. As an aside, I know it doesn't make much sense here but it's one of those use-cases I've seen in the version we wrote at work and wanted to future proof myself against. By taking it into account as part of the initial framework construction, I think I've set myself up better for the future than the solution that has evolved overtime at work. Unfortunately I'm not sure it's a solution that can be taken back into work to solve that problem better at this point.
  6. The starship data knows how to replace “Name” tags with its display name “USS Enterprise” and because of the scoping rules it finds the tag “Starship:Name” is empty so it fills it in.
    1. “Is empty”, because someone's got to win ties. If somehow two things want to replace the same tag either every one writes to the entry, in which case whoever's second wins, or things should only write if the entry is empty, in which case whoever's first wins. It's a bit arbitrary which is which, but I'm again leveraging experience building this system at work where empirically we got better results by having it be a first-come-first-serve basis.
  7. Everything unwinds to the text injection process and it uses the UE4 formatting to replace “{Starship:Name}" with the map element “USS Enterprise” to generate output text of “Repair USS Enterprise”.

The other improvement I feel I've made over the version we wrote at work was to introduce an actual interface for “things that can be resolvers”. Because of my immediate use case, only the transaction definition, transaction parameters (which is the base for input and output parameters) and the starship data implement that interface. Also, the only tag that any type knows how to replace is “Name” from the starship data. This interface will obviously be applied more widely and more tags will be supported as the project continues.

Another interface I added was one for getting display information, specifically names, descriptions and icons. Different types may have different variable names or storage requirements for this data and an interface provides the simplest way to have a unified API for some more generic programming elements. In this case I've initially implemented it from the Damage Status so that the dropdown for the repair dialog can be populated in a way that doesn't require knowing the definition type. This way I can keep that widget and the overall dialog generically usable by any transaction and not just the repair project. I'll want to expand on the implementation and use of this interface in the future.

August '20 Goals

This sprint I would like to finish up the odd and ends of the work I did in July. Originally that list of work was longer, but then I finished a little early and was able to get to those things as part of July instead of pushing it out to August (like the text injection work).

  • Update the display of the list of active projects to be supported by text injection so that it can properly show “Repair USS Enterprise” (or whatever the shipname happens to be) instead of “Repair {Starship:Name}”
  • Redo starship construction. When I'd originally made the transactions for building new starship, I'd included the costs directly in the transaction. I always figured that wouldn't work long term so it's time to pay the piper on this one. I need to move the construction costs to the starship definition. This will allow me to do a couple of nice things
    1. Reduce the number of construction transactions required which would otherwise have become annoyingly large. Because of the cost location, I have to make a unique transaction for every ship class the player would be allowed to build (which should be more or less all of them).
    2. Build loot tables for destroying (or scraping) ships that are based on the initial construction cost in a more coherent way.
    3. Setup the costs of the repair transactions based on initial construction cost in a coherent way
  • Expand the transaction system even more so that the input parameters have a mechanism to influence the duration of projects they may be a part of. This way I can still have a single repair project while still having a way to make repairing a crippled starship take longer than repairing someone with only light damage. In addition, the project related code and UIs will need to be updated to allow for showing ranges. The initial use case would be that the repair project would show the low to high estimate when there are multiple target repair levels.
  • I've started to run into problems with my iteration. All during this last sprint I was testing repairs which required damaging my starships → which requires going into tactical → which requires going on a mission → which (at the moment) requires navigating to a new star system. I really should have written a console command sooner, but I felt it was too much of a distraction to what I was trying to work on. But now I should rectify that issue and plan to make two strategy related console commands:
    1. Randomly apply damage statuses to all the starships I currently control.
    2. Create a new mission in the star system that the player is currently in.
  • Lastly I've got a few different debt issues I would like to address as “stretch” goals should the above tasks not take up all the time or I have smaller blocks of time available to work and don't want to get too heavily involved in something too complicated.

Quite honestly I also really want to get started on a paper doll type UI for configuring a ship's systems (instead of the boring dropdowns it's doing now), but I don't quite think I'll get to it. I've marked it down for the September sprint, but maybe it'll be a “stretch-stretch” goal.

Reading

I decided to start re-reading the Honor Harrington series and I've already finished the first three. It's been quite a while since I had read a lot of the earlier books plus, for once, I ran out of fiction books in my backlog so it seemed a good opportunity. For those not familiar with it, it's a hard SciFi military series is by David Weber and follows the naval career of the series namesake Honor Harrington. There are great space battles and because of the time span the series covers in the 16+ books, you see a wonderful progression of tactics, technology, characters and politics. It's probably one of the key, non-game, sources of inspiration for this project.

0 likes 0 comments

Comments

Nobody has left a comment. You can be the first!
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement
Advertisement