Here's my idea for the syntax for checkpoints and "refined" tutorial messages (That is, tutorial messages using this syntax. Levels with names starting with "tutorial" can still use the old syntax). It's a modified version of the syntax I posted in
jebby's Checkpoints topic.
Checkpoints and refined tutorial messages don't have to be declared in the level code like the old tutorial messages. Rather, they are declared on separate lines beginning with the "!" (exclamation point) character. The two recognized "!" commands: "!cp(id)" for checkpoint and "!msg(id, message)" for tutorial message. They both have an ID parameter, which is an integer used to identify this event. IDs do not have to be unique - you can have multiple checkpoints and/or messages with the same ID. Tutorial messages defined in the old syntax with have IDs 0-9, the same as the number used to place them in the level. The message parameter for "!msg()" is the message to be displayed to the user. Specifically, I will grab any characters between "," and ")", remove any spaces at the beginning and end, and then remove the first and last character if they are single or double quotes.
After the command defining the event, you define when the event should trigger with a space-separated list of requirements (and/or modifiers). Here are the ones I have planned so far:
Code:
at(x, y) - Met if Hannah is at the specified location. Identical to placing the ID at that location in the level code in the old tutorial message syntax. The coordinates count up from the top left corner, which is (1, 1)
in(x1, y1, x2, y2) - Met if Hannah is within the specified rectangular area
treasures(count) - Met if count or more treasures have been collected
tile(x, y, value) - Met if the tile at (x, y) is the specified value ("value" being a character of HATPC level code, such as "+" for treasure). This will detect crates mid-fall and boulders mid-roll the way I'm planning to implement it (since it'll be better for performance that way)
id(type, value) - There will be 3 different types of ID requirements. Type = "skip" will only trigger if no event of ID greater than or equal to "value" has been triggered. Type = "prereq" will only trigger if an ID greater than or equal to "value" has been triggered. Type = "exact" will only trigger if an event with ID of *exactly* "value" has been triggered.
multi() - A modifier that allows this event to be triggered multiple times, so long as the last event to be triggered was not an event with the same ID as this one. Be a bit careful with this one, because if two events with "multi()" have different IDs and all the requirements of both are met, the game will crash or freeze, since it'll create an infinite loop. Although I suppose if you wanna be evil you could use that to create invisible objects that crash the game if you touch them. :P
Examples:
In this syntax, the first tutorial message on tutorial level one would be
Code:
!msg(0, "Climb up the rocks to the right by jumping. The green arrows will guide you to the end of the level. And don't worry - nothing can hurt you on this level!") at(7, 21)
Rather than having the "Oops! You fell into a hole!" message in tutorial one repeat every time you enter a different hole (at least twice if you collect the gem), it could be set to skip additional messages after the first one is triggered by setting "id(skip, 6)" or by replacing the separate events with one event with an "in()" region that covers all the holes.
And rather than displaying the "Hmm.. looks like you're stuck." message in tutorial 3 when you climb up the boulder cascade, it could be displayed as soon as the way through is blocked off and Hannah has not gone across by testing Hannah's position with an "in()" region and the boulders' state with "tile(24, 24, o)". The same goes for the "Phew! That was close." message, it can wait to be triggered until the boulders have fallen down and blocked the way back. Then those two messages can be made mutually exclusive by giving them the same ID and a "id(skip, value)" clause so that once one has triggered, the other is disabled.
There are a lot more applications, but I'll leave those up to the level designers to come up with.
Let me know what you think of this syntax. I think it's flexible enough to do pretty much anything, but also pretty easy to use and understand (as much as it can be). Actually, I just thought of another requirement I could add: "gem()" to trigger only if the gem has been collected.