RPG Development Log #4

I’ve been meaning to write this blog post for a while! Looking back at the commit history, this was done nearly a month ago! As mentioned last time, the plan was to work on adding choice selection to the user. And that’s exactly what happened!

Choice Menu

At first glance the choice system seemed like something that should be an extension of the messaging system. “All” that would require would be adding a few parameters to the current interfaces, adding some new display code, and adding new logic to handle user input. Okay so that might actually be a lot. I was part way through with this change and ended up starting from scratch for a couple of reasons.

Reusability

Choices may not exclusively appear accompanying a message box. They could be on their own. They could appear in a menu. If they can appear in those places, there are probably several others that would also be useful. I’d rather spend a little bit of extra time decoupling the implementation now and be able to use it later than have to refactor it when I’m less familiar with it.

Simplicity

In fact I may have saved time by splitting up the functionality. With the features compartmentalized into their own sections, I didn’t have to worry about edge cases of “What if a message is still displaying and a choice is chosen?”, or “Does pressing enter mean the player wants to advance messages or select a choice?”. The previous work on the state machine made this dead simple. I hooked up the new input controller, added a new state along with some triggers, and called it a day.

Testability

Since the code was simpler it was also a heck of a lot easier to test! I like getting to spend more time adding functionality than testing so this was a big deal.

Example Usage

await MessageDisplayManager.DisplaySet(new[] {
	new Message("Don't stop I have more to say!", async () => {
		var a = new Choice("option 1");
		var b = new Choice("option 2 is long");
		var c = new Choice("3");
		Choice selection = await ChoiceDisplayManager.DisplaySet(new[] {a, b, c});
		MessageDisplayManager.AdvanceToNextMessage();

		await MessageDisplayManager.DisplaySet(new[] {
			new Message($"You chose \"{selection.DisplayText}\"")
		});
	})
});

We can see that an arbitrary number of choices can be sent to the ChoiceDisplayManager and DisplaySet will return whichever choice was select. It supports async / await as well. That code translates into the functionality shown below.

Plot Menu

With the menu out of the way, it wasn’t all that much effort to have the ability to dynamically replace buildings based off the player’s choice. All of the logic was abstracted into a single function call.

public override async Task Interact(ICharacter initiator) {
	await _buildingManager.DisplayBuildingMenu(this);
}

The building manager is responsible for keeping track of all the different buildings that are buildable. In the future this will also be in charge of restricting which buildings can be built by the player based of a variety of criteria (e.g. A quest may need to be completed before a more efficient structure can be built). It will also be be in charge of displaying stats and prices to the player.

Next Steps

This functionality goes a long way into making the core mechanics of the game more visible. Multiple plots can be placed trivially, and the options start expanding. Next on the docket is either saving the state of the game to a file, or implementing a rudimentary form of the citizen pathfinding logic.

Until next time.