2015-01-31

January Wrap Up. Screen Shot Sat, Mission System, etc.

January

I think this was a good start to the year. I've added a bunch of things to the system and designed a lot of stuff for Crooked that should keep me busy through the rest of the year. Looking back on my posts to this blog, in January I did this:
  • put together basic documentation for Fate
  • transferred NDGA to the system (although I don't think I'll release the updated version because it is incomplete)
  • added basic horizontal lines with variable width
  • added a fancy text style and text alignment
  • added watching variables for changes and toast messages
  • added the stat display for viewing variables
  • added input and toggles to variables
  • added print() transformations using Humanizer
  • put together Body Gen and released it for peoples to try
  • added descriptive text within links
  • added an sms text style
  • and finally I added the mission system and added icons to the main game screen for prettyness.
 There are probably more things in between all of that stuff, but I can't remember any of it.


Mission System



The mission system is pretty simple right now. The important thing is that it works (kinda). So this is how you define a mission in the source code:
:: Defeat Some Boss [mission(Primary)]
A powerful, evil boss is messing up the land. You should do something about it.
I thought the declaration should look familiar to other top level structures in the system, so the core difference is the mission() function in the tag area of the header line. That probably sounds like gobbledygook, but really there is a method to the madness ... somewhat.

The stuff on the left is the mission title and the arguments of the mission() function is a text category for the mission. The category will eventually be a way to group like missions in the interface, but that will be implemented later down the road. The text that follows the header is the description for the mission. I thought that it could operate like normal passage text, but for now it doesn't evaluate functions like print() or line(). The description does have the capability of being more specific by using criteria()
:: Defeat Some Boss [mission(Primary)]
A powerful, evil boss is messing up the land. You should do something about it.

criteria($askedLocals == enum.yes)
A powerful, evil boss is messing up the land. Now that you've asked the locals about the boss, go find the boss hideout.
From here all we really need to do is start the mission.
mission(Open, Defeat Some Boss)
And once the mission is complete.
mission(Succeed, Defeat Some Boss)
We can also Fail or Disable the mission as needed.

This is all fine, but usually missions or quests are made up of a bunch of individual steps. I'm representing these as tasks.
:: Defeat Some Boss [mission(Primary)]
A powerful, evil boss is messing up the land. You should do something about it.


criteria($askedLocals == enum.yes)
A powerful, evil boss is messing up the land. You should do something about it. Now that you've asked the locals about the boss, go find the boss hideout.


task($askedLocals == enum.yes)
- Ask the locals about the boss.

Tasks are basically criteria that need to be met to be considered complete, and a description of the task. Because I'm crazy I thought the task descriptions should also use criteria() to be more specific if needed.
task($askedLocals == enum.yes)
- Ask the locals about the boss.

criteria($askedLocals == enum.yes)
- The locals told you where the hideout is.



So missions can be made up of a series of these tasks.
:: Defeat Some Boss [mission(Primary)]
A powerful, evil boss is messing up the land. You should do something about it.


criteria($askedLocals == enum.yes)
A powerful, evil boss is messing up the land. Now that you've asked the locals about the boss, go find the boss hideout.


task($askedLocals == enum.yes)
- Ask the locals about the boss.


criteria($askedLocals == enum.yes)
- The locals told you where the hideout is.
The mission needs to be turned on, then it will update it's status by checking each of it's tasks for completion. You can still manually mark a mission as passed or failed but the tasks exist to make the missions self maintained after being opened. As more tasks are added there needs to be some way of making sure tasks are only visible after other tasks are complete. Instead of having tasks know directly about each other, I've set it up so that individual tasks just use criteria to determine visibility. This is done by using require()
task($foundHideout == enum.yes)
require($askedLocals == enum.yes)
- Find the bosses hideout.
This way tasks only show in the interface once the right conditions are met, similar to how verbs work. This also makes me think I should change criteria() within links to require() for consistency.

Anyway, there are sometimes multiple ways to make progress in a mission. To represent tasks that are one of several that could be done to make mission progress, I added a new function optional() that takes a number for the group that it belongs to.
task($knowBossIsInHideout == enum.yes)
require($foundHideout == enum.yes)
optional(enum.optionalKnowsWhenBossIsInHideout)
- Wait and watch for the boss to enter the hideout.


task($knowBossIsInHideout == enum.yes)
require($foundHideout == enum.yes)
optional(enum.optionalKnowsWhenBossIsInHideout)
- Ask the shopkeeper about when the boss enters the hideout.

That enum stuff evaluates to a number, but I like wordy descriptions for these things. optional() is also useful in cases where a particular task isn't required to complete to finish the mission should be visible to the player.
task($recoveredShield == enum.yes)
require($knowsAboutShield == enum.yes)
optional()
- Recover the jeweled shield from the boss

That pretty much covers how the system works in the source. Here is the final code and a gif of it in action.
:: Test Missions
this is a test of the mission system.
[[Start Mission]]


:: Start Mission
mission(Open, Defeat Some Boss)
You heard there was an evil boss rampaging across the land.
[[Ask the locals]]


:: Ask the locals
set($askedLocals = enum.yes)
You ask the locals about the boss. They tell you where the bosses lair is.
[[Find the hideout]]


:: Find the hideout
set($foundHideout = enum.yes)
You find the bosses hideout where the locals told you it would be.
[[Wait for the boss to enter]]
[[Ask the shopkeeper about the boss]]


:: Ask the shopkeeper about the boss
set($knowBossIsInHideout = enum.yes)
set($knowsAboutShield = enum.yes)
You ask the shopkeeper about the boss. They tell you when to find the boss at the hideout. You go to the hideout when the shopkeeper says and see the boss.
[[Fight the boss]]


:: Wait for the boss to enter
set($knowBossIsInHideout = enum.yes)
You wait for the boss to enter the hideout. The boss finally enters the hideout.
[[Fight the boss]]


:: Fight the boss
set($defeatedTheBoss = enum.yes)
You fight the boss and win.
[[Start]]


:: Defeat Some Boss [mission(Primary)]
A powerful, evil boss is messing up the land. You should do something about it.


criteria($askedLocals == enum.yes)
A powerful, evil boss is messing up the land. Now that you've asked the locals about the boss, go find the boss hideout.


task($askedLocals == enum.yes)
- Ask the locals about the boss.


criteria($askedLocals == enum.yes)
- The locals told you where the hideout is.


task($foundHideout == enum.yes)
require($askedLocals == enum.yes)
- Find the bosses hideout.


task($knowBossIsInHideout == enum.yes)
require($foundHideout == enum.yes)
optional(enum.optionalKnowsWhenBossIsInHideout)
- Wait and watch for the boss to enter the hideout.


task($knowBossIsInHideout == enum.yes)
require($foundHideout == enum.yes)
optional(enum.optionalKnowsWhenBossIsInHideout)
- Ask the shopkeeper about when the boss enters the hideout.


task($recoveredShield == enum.yes)
require($knowsAboutShield == enum.yes)
optional()
- Recover the jeweled shield from the boss


task($defeatedTheBoss == enum.yes)
require($knowBossIsInHideout == enum.yes)
- Kill the evil boss.



Plans

So with all of that done, it's time I start writing the actual game. I'm taking off the code hat for a while and putting on my stained writers cap. Yeah even while typing that I second guessed if I should use writers or writer's. I initially went with writer's then thought about it, then flipped a coin. ....

Right ... so Febuary is my righters month. All words and no code .... yeah ........ maybe a little code <_<

EDIT: I picked up a bug looking at the screenshots. Turns out I wasn't applying criteria() to tasks properly. Fixed that, but that's it. No more coding .... >_>

No comments:

Post a Comment