Text manipulation in Quake (part III): Parameters

Solutions

So some quick solutions to the homework from part II. All the functions:

void(float c) S_Print_Goldnum =
{
 if(c >= '0' && c <= '9')
 c = c - 30;
 WriteByte (MSG_ONE, c);
}

void(float c) S_Print_Caps =
{
 local float c_low;
 c_low = c & 127; //clear the highest bit
 if( c_low >= 'a' && c_low <= 'z')
 c = c - 32;
 WriteByte (MSG_ONE, c);
}

void(float c) S_Print_Spaced =
{
WriteByte (MSG_ONE, c);
WriteByte (MSG_ONE, ' ');
}

S_Print_Caps uses a bit of a trick to deal with the white and red at once. By clearing the highest bit on the character, the red letters are converted to their white counterparts, so we can test both with the same code. The solution to part 4) should be straightforward, the only trick is to ensure the code for writing the date precedes the line which terminates the centerprint with a zero byte.

Parameters

Our new system for printing to the screen lets us change a piece of text dynamically. So it seems natural to add a parameter to our S_ functions to take advantage of it. There are two technical obstacles in our current setup; the first is that we’d have to change the signature of all of our T_ functions to take a different kind of function pointer. The second is that because we don’t call the S_ functions directly, so we’d have to pass the value of the parameter through the T_ function. This mean you can’t have S_ functions with different parameters, unless you also have multiple T_ functions to match.

So we’re going to leave all the definitions we’ve made so far alone, and instead pass parameters to the S_ function using a global instead. Now, there are pitfalls when using globals to pass values. The main one is that it’s not safe if you might call functions recursively, as the inner call will overwrite the globals, causing trouble when the outer call gets control again. However, we already use a global: the msg_entity is a global value. So we aren’t making things worse with this approach.

We’re going to add a function S_Print_Splitflap which caps the character values it prints to a maximum value, using a parameter to control the maximum. The goal is to create text that behaves like a split-flap board. Start with the code from part II, and add this function.

float S_Print_Splitflap_Gate;
void(float c) S_Print_Splitflap =
{
	if(c > S_Print_Splitflap_Gate && c < 128)
		c = S_Print_Splitflap_Gate;
	WriteByte (MSG_ONE, c);
}

Also replace all of our printing code from PlayerPostThink with the following:

msg_entity = self;
WriteByte (MSG_ONE, SVC_CENTERPRINT);
S_Print_Splitflap_Gate = 'e';
T_Location(S_Print_Splitflap);
S_Print_Splitflap(0);

When you run this, you should get “Meeaee Deeeee, 16:30. Try changing the constant 'e' to different values like 'D','m','2' and 'z' to see how the output changes.

Once you’ve got a feel for what the function does, it’s time to animate it. Change the whole line to S_Print_Splitflap_Gate = time + ' ';. Run your code again and you should see all the characters in the phrase cycle, and eventually settle on their final values.

If you’re anything like me you’ll lose the patience to see the message unroll all the way to the end. We can speed up the message as follows:
S_Print_Splitflap_Gate = time * 24 + ' ';
Much better!

Homework

1) Add a second parameter called S_Print_Splitflag_Floor which set the minimum character value which will be printed, and set it to 'E' in PlayerPostThink as a test.
2) Modify the code in 1) so that instead of printing the character in S_Print_Splitflag_Floor, the function prints ' ' for any character above 127.
3) Modify the code in 1) so that S_Print_Splitflag_Floor increases as time passes, allowing the entire message to disappear eventually. Tweak the timing values so that no characters fall below the Floor until the whole message is under the Gate.

Hint for 3) – it doesn’t matter if S_Print_Splitflag_Floor is negative to begin with, as long as the code in 1) is correct.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s